Laravel Spy未调用原实现?测试返回null问题排查
问题:Laravel测试中使用Spy后原方法未执行返回null
我有Foo和Bar两个类:
class Foo { private Bar $bar; public function __construct(Bar $bar) { $this->bar = $bar; } public function foo() { return $this->bar->bar(); } } class Bar { public function bar() { Log::info('bar was called'); return 42; } }
原本的测试可以正常验证foo()返回42:
public function test_foobar() { $foo = $this->app->get(Foo::class); $this->assertEquals(42, $foo->foo()); }
但我想额外验证foo()调用了bar(),于是改用Spy:
public function test_foobar() { $spy = $this->spy(Bar::class); $spy->shouldReceive('bar')->once(); $foo = $this->app->get(Foo::class); $this->assertEquals(42, $foo->foo()); }
此时测试失败,$foo->foo()返回null,而且Bar的bar()方法根本没执行(没有日志输出)。我以为Spy会保留原方法的执行逻辑,请问哪里错了?
注:我不想mockbar()的返回值,希望保留原有行为。
问题原因
调用shouldReceive('bar')->once()后,Laravel依赖的Mockery Spy会默认替换原方法的实现,不再执行真实逻辑,所以返回null,也不会输出日志。
解决方案
要让Spy保留原方法的行为,需要在shouldReceive后链式调用andCallThrough(),它会告诉Spy在记录调用次数的同时,执行原方法的逻辑:
public function test_foobar() { $spy = $this->spy(Bar::class); // 添加andCallThrough(),保留原方法执行 $spy->shouldReceive('bar')->once()->andCallThrough(); $foo = $this->app->get(Foo::class); $this->assertEquals(42, $foo->foo()); }
这样修改后,Spy会同时完成两个任务:
- 验证
bar()被调用了一次 - 执行
bar()的真实逻辑,返回42并输出日志
内容的提问来源于stack exchange,提问作者Enno
相关产品推荐
相关产品推荐

