PHPUnit+Mockery测试中,为何无法断言Mock方法已被调用?
问题分析:Mockery断言失败,提示
setXY未被调用 问题场景
创建了依赖Setter注入的MyService类:
namespace App\Services; class MyService { private $anotherService; public function setService(AnotherService $anotherService) { $this->anotherService = $anotherService; } public function getService() { if(empty($this->anotherService)){ $this->setService(new AnotherService()); } return $this->anotherService; } public function call() { $anotherService = $this->getService(); $anotherService->SetXY(5,10); } }
依赖类AnotherService:
namespace App\Services; class AnotherService { public function SetXY($x,$y) { } }
编写的PHPUnit+Mockery测试用例:
namespace Tests\Services; use App\Services\MyService; use App\Services\AnotherService; use PHPUnit\Framework\TestCase; use Mockery; class MyServiceTest extends TestCase { public function testService() { $mockedAnotherService = Mockery::spy(AnotherService::class); $mockedAnotherService->shouldReceive('SetXY'); $service = new MyService(); $service->setService($mockedAnotherService); $service->call(); $mockedAnotherService->shouldHaveReceived()->setXY(5,10); } }
执行测试后报错:
1) Tests\Services\MyServiceTest::testService Mockery\Exception\InvalidCountException: Method setXY(<Any Arguments>) from Mockery_0_App_Services_AnotherService should be called at least 1 times but called 0 times. /var/www/html/api/vendor/mockery/mockery/library/Mockery/CountValidator/AtLeast.php:47 /var/www/html/api/vendor/mockery/mockery/library/Mockery/Expectation.php:310 /var/www/html/api/vendor/mockery/mockery/library/Mockery/ReceivedMethodCalls.php:46 /var/www/html/api/vendor/mockery/mockery/library/Mockery/VerificationDirector.php:36 /var/www/html/api/vendor/mockery/mockery/library/Mockery/HigherOrderMessage.php:46 /var/www/html/api/tests/Services/MyServiceTest.php:23 phpvfscomposer:///var/www/html/api/vendor/phpunit/phpunit/phpunit:60
原因解析
核心问题是方法名的大小写不匹配:
- 在
MyService的call方法中,实际调用的是大写首字母的SetXY(5,10) - 但测试用例中断言的是小写首字母的
setXY(5,10)
PHP是大小写敏感的编程语言,Mockery会严格匹配方法名的大小写,因此这两个被判定为完全不同的方法,导致断言时认为setXY从未被调用。
解决方案
方案1:修正测试用例的断言方法名
将测试中的断言方法名改为与实际调用一致的SetXY:
$mockedAnotherService->shouldHaveReceived()->SetXY(5,10);
方案2:遵循PSR规范统一方法名(推荐)
按照PHP的PSR编码规范,类方法名应使用小写开头的驼峰命名,因此修改AnotherService的方法名,并同步修改MyService中的调用:
- 修改
AnotherService:
namespace App\Services; class AnotherService { public function setXY($x,$y) { } }
- 修改
MyService的call方法:
public function call() { $anotherService = $this->getService(); $anotherService->setXY(5,10); }
此时测试用例中的断言无需修改,即可正常通过。
内容的提问来源于stack exchange,提问作者Dimitrios Desyllas
相关产品推荐
相关产品推荐

