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

Mock中对被其他函数调用的函数设置shouldReceive断言未生效,如何解决?

为啥你的Mock里bar()的断言永远不生效?

兄弟,我一眼就看出问题所在了——你对Mock的核心逻辑理解错了!当你创建一个**完整Mock(Full Mock)**的时候,这个对象的所有方法都会被替换成空的Mock实现,包括你写的foo()方法本身!

也就是说,你原类里foo()中判断$value instanceof SomeClass然后调用bar()的逻辑,根本就没执行!因为Mock的foo()是个空架子,不会走原来的代码,自然不会触发bar()的调用,那你的shouldReceive('bar')或者shouldNotReceive('bar')当然永远不会生效啦。


问题根源

你现在的Mock把整个类的方法都覆盖了,原类的业务逻辑完全没跑。Mock的本质是模拟外部依赖的行为,或者验证方法的调用情况,但如果你Mock的是你要测试的类本身,又想保留部分方法的原逻辑,就不能用普通的Full Mock。


正确的做法

1. 使用Partial Mock(部分Mock)

Partial Mock会保留原类的方法实现,只Mock你需要监控或者替换的方法。比如用Mockery的话:

// 创建部分Mock,保留原类的方法逻辑
$mock = Mockery::mock(YourClass::class)->makePartial();

// 根据传入的$suppliedValue设置断言
if ($suppliedValue instanceof SomeClass) {
    // 预期bar()会被调用一次
    $mock->shouldReceive('bar')->once()->with($suppliedValue);
} else {
    // 预期bar()不会被调用
    $mock->shouldNotReceive('bar');
}

// 执行测试方法
$mock->aFunctionThatCallsFoo($suppliedValue);

这样foo()会执行原有的判断逻辑,当满足条件时会调用bar(),这时Mock的bar()断言就能正确触发了。

2. 直接测试foo()方法(更推荐)

如果你的测试目标是验证foo()在不同参数下是否正确调用bar(),那没必要绕弯子调用aFunctionThatCallsFoo,直接实例化原类,传入不同的参数,用Spy来监控bar()的调用:

// 创建Spy对象,它会记录所有方法调用
$spy = Mockery::spy(YourClass::class);

// 直接调用foo()
$spy->foo('test-key', []);
// 验证bar()没被调用
$spy->shouldNotHaveReceived('bar');

// 再传一个SomeClass实例
$someClass = new SomeClass();
$spy->foo('test-key', $someClass);
// 验证bar()被调用了一次,参数正确
$spy->shouldHaveReceived('bar')->once()->with($someClass);

Spy比Partial Mock更适合这种监控内部方法调用的场景,因为它默认保留所有原方法逻辑,只是记录调用情况。


最后再敲个黑板

记住:Full Mock会替换所有方法,原逻辑完全不执行;Partial Mock/Spy会保留原逻辑,只监控或替换指定方法。你之前的问题就是用了Full Mock,导致foo()的内部逻辑根本没跑,自然触发不了bar()的断言。

内容的提问来源于stack exchange,提问作者Edwin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:50:38