我正在尝试使用 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
我认为您通过模拟
getAttribute()
来使用模型模拟有点不正确。测试中经常发生的情况是,您使用 Laravel 工厂创建一些模拟模型,例如 $model = User::factory()->create()
,它应该正确设置属性。
您所看到的行为可能来自以下事实:在 Eloquent 模型内部,所有属性实际上都是
protected array $attributes
数组的一部分,并且由于一些魔法 __get()
它们被检索。
所以我相信,如果您通常构造模拟对象(因此使用
YourModel::create()
通过工厂调用或在测试中手动调用),它应该按预期工作。
编辑:现在我正在写这个,你也许可以通过模拟 Eloquent 模型上受保护的
$attributes
属性并以这种方式设置属性。但这样做有点奇怪。