
本文详解在 phpunit 9 中 mock 类方法时仍触发实际执行的常见原因及解决方案,重点说明 disableoriginalconstructor() 的必要性、mock 对象的正确注入方式,并提供可直接运行的完整示例代码。
本文详解在 phpunit 9 中 mock 类方法时仍触发实际执行的常见原因及解决方案,重点说明 disableoriginalconstructor() 的必要性、mock 对象的正确注入方式,并提供可直接运行的完整示例代码。
在使用 PHPUnit 9 进行单元测试时,一个典型误区是:仅创建 mock 对象并设置期望行为,并不自动阻止原方法执行——前提是该 mock 实例未被真正用于被测逻辑中。你遇到的 Twilio\Exceptions\RestException: [HTTP 403] 错误明确表明:retrieveLastTextFromBot() 方法仍在执行其内部 Twilio SDK 调用,说明测试中实际调用的对象并非你创建的 mock,而是原始类实例(或其依赖未被正确替换)。
✅ 正确做法:确保 mock 实例被真实注入
Mock 的核心原则是 “替换依赖”,而非“拦截任意同名方法”。以下为关键步骤:
-
禁用原始构造函数(关键!)
若被 mock 类(如 Twilio)有构造依赖(如 Twilio\Rest\Client),必须调用 ->disableOriginalConstructor(),否则 PHPUnit 会尝试实例化真实对象,导致构造阶段就失败或后续方法调用绕过 mock:$twilioStub = $this->getMockBuilder(Twilio::class) ->disableOriginalConstructor() // ← 必须添加! ->getMock(); -
显式设置期望行为
在 mock 创建后,立即定义方法调用预期与返回值:$message = (object)['body' => 'This won\'t exist']; $twilioStub->expects($this->once()) ->method('retrieveLastTextFromBot') ->willReturn($message); -
将 mock 注入被测系统(SUT)
确保业务逻辑使用的 Twilio 实例是你创建的 mock,而非 new Twilio(...) 或容器自动解析的真实实例:// 正确:SUT 显式接收 mock $sut = new CronController($twilioStub); // 假设构造器接受 Twilio 实例 $sut->remind(); // 此时调用的是 mock 的 retrieveLastTextFromBot()
❌ 错误示例(常见陷阱):
// 若 CronController 内部自行 new Twilio(...) 或从全局容器取实例, // 则你的 mock 完全未被使用! $twilioStub->retrieveLastTextFromBot(); // 单独调用 mock 是 OK 的, $sut = new CronController(); // 但 SUT 仍用真实 Twilio!
? 排查技巧:确认方法调用来源
若仍不确定哪段代码触发了真实方法,可在生产方法开头加入调试断点:
立即学习“PHP免费学习笔记(深入)”;
public function retrieveLastTextFromBot()
{
// 临时添加,运行测试后立即终止并输出调用栈
echo "Called from: " . debug_backtrace()[0]['file'] . ":" . debug_backtrace()[0]['line'] . "\n";
exit(1);
// ... 原有逻辑
}若输出显示调用来自 CronController.php(而非测试文件),说明 CronController 并未使用你创建的 $twilioStub,需检查其初始化方式——应通过构造函数/Setter 注入,而非硬编码实例化。
? 总结要点
- Mock 不等于全局拦截:它只对 该 mock 实例 的方法调用生效;
- disableOriginalConstructor() 是高频必需项,尤其当类有外部依赖时;
- 注入即信任:确保被测类(SUT)持有的依赖对象,就是你配置好期望行为的 mock;
- 避免静态调用或单例模式:它们会绕过依赖注入,使 mock 失效;
- 使用 composer show -i | grep phpunit 确认 PHPUnit 版本(本文基于 9.x),API 兼容性至关重要。
遵循以上实践,即可彻底避免 mock 方法被真实执行,让测试真正聚焦于业务逻辑验证。



















