如何在 PHP 中模拟对象以正确使用空合并运算符 (??)?

问题描述 投票:0回答:1

我正在尝试使用 Mockery 编写 PHPUnit 测试,并且在使用具有模拟属性的空合并运算符 (??) 时不断遇到问题。具体来说, ??似乎总是返回 null,这会导致 ??运算符回退到默认值,即使该属性已正确模拟并返回一个值。 这是我的设置的简化版本:

public function testExample()
{
    $model = Mockery::mock(Model::class)->shouldIgnoreMissing();

    // Mocking a property
    $model->shouldReceive('getAttribute')
        ->with('title')
        ->andReturn('Test Page');

    $model->title = 'Test Page'; // I also tried this

    $result = $this->doSomething($model);

    $this->assertEquals('/test-page', $result);
}

public function doSomething($model): string
{
    print_r([$model->title, $model->title ?? 'default']);
    ...
    ...
}

输出:

Array
(
    [0] => Test Page
    [1] => default
}

当我直接使用 $model->title 时,它工作正常并返回模拟值(“测试页”)。但是,当我尝试使用 $model->title ?? 'default',始终返回后备('default'),就好像 title 属性不存在或为 null。

有没有办法让空合并运算符 (??) 与 PHP 中的 Mockery 模拟一起可靠地工作?

请注意,我正在使用 PHP 8.2、phpUnit 10.5 和 Laravel 11.33.2

php laravel phpunit mockery
1个回答
0
投票

我认为您通过模拟

getAttribute()
来使用模型模拟有点不正确。测试中经常发生的情况是,您使用 Laravel 工厂创建一些模拟模型,例如
$model = User::factory()->create()
,它应该正确设置属性。

您所看到的行为可能来自以下事实:在 Eloquent 模型内部,所有属性实际上都是

protected array $attributes
数组的一部分,并且由于一些魔法
__get()
它们被检索。

所以我相信,如果您通常构造模拟对象(因此使用

YourModel::create()
通过工厂调用或在测试中手动调用),它应该按预期工作。

编辑:现在我正在写这个,你也许可以通过模拟 Eloquent 模型上受保护的

$attributes
属性并以这种方式设置属性。但这样做有点奇怪。

© www.soinside.com 2019 - 2024. All rights reserved.