如何在PHPUnit中不使用依赖注入实现Mock测试?
问题解答
为啥你的Mock没生效,测试还通过了?
你的Check::checkAdd方法里是直接在内部new了真实的Calculator实例,和你在测试里创建的Mock对象完全是两个独立的东西。真实的Calculator::add返回5+2=7,和你计算的sum值相等,所以assertTrue($result)自然会通过。
不使用依赖注入,怎么让测试用上Mock值?
对于硬编码在方法里的new Calculator(),要替换成Mock对象,有两种实用方案:
方案1:用PHPUnit Mock + 类别名替换
先创建Calculator的Mock,然后通过class_alias让Calculator这个类名指向你的Mock类,这样当Check方法里执行new Calculator()时,实际创建的是Mock实例。
修改后的测试代码:
public function testValidateAdd() { // 创建Calculator的Mock,指定只mock add方法 $calculatorMock = $this->getMockBuilder(Calculator::class) ->onlyMethods(['add']) ->getMock(); // 设置Mock的add方法返回3 $calculatorMock->method('add')->willReturn(3); // 让系统把Calculator类名指向我们的Mock类 class_alias(get_class($calculatorMock), 'Calculator'); $check = new Check(); $result = $check->checkAdd(5, 2); // 此时sum是7,Mock返回3,$result为false,断言会失败(符合你的预期) $this->assertTrue($result); }
注意:这种方式会影响整个测试进程中的Calculator类,建议在测试结束后用class_alias重新指向真实的Calculator类,或者在tearDown方法里清理。
方案2:用匿名类临时替换(更轻量)
创建一个继承自Calculator的匿名类,重写add方法返回你想要的值,再通过类别名替换,效果和Mock一致:
public function testValidateAdd() { // 创建匿名类重写add方法 $mockCalculator = new class extends Calculator { public function add($num1, $num2) { return 3; } }; // 替换Calculator类名指向匿名类 class_alias(get_class($mockCalculator), 'Calculator'); $check = new Check(); $result = $check->checkAdd(5, 2); $this->assertTrue($result); // 断言失败,符合预期 }
题外话:为啥推荐用依赖注入?
你现在遇到的测试困难,本质是代码紧耦合导致的——Check直接绑定了Calculator的具体实现,而不是依赖抽象。依赖注入(构造注入、方法注入)是解决这类问题的标准方案,比如修改Check类:
class Check { private $calculator; // 构造注入Calculator实例 public function __construct(Calculator $calculator) { $this->calculator = $calculator; } public function checkAdd($num1, $num2) { $sum = $num1 + $num2; $res = $this->calculator->add($num1, $num2); return $sum == $res; } }
这样你的原测试代码就能直接生效,而且代码耦合度更低,后续扩展或替换Calculator实现也更方便。
内容的提问来源于stack exchange,提问作者sparkmix
相关产品推荐
相关产品推荐

