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

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中的调用:

  1. 修改AnotherService:
namespace App\Services;

class AnotherService
{
    public function setXY($x,$y)
    {

    }
} 
  1. 修改MyService的call方法:
public function call()
{
    $anotherService = $this->getService();

    $anotherService->setXY(5,10);
}

此时测试用例中的断言无需修改,即可正常通过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:01:20