You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 08:03:21