Mockery中mock()->makePartial()链式调用shouldReceive报错原因
问题根因
这不是makePartial()方法的问题,是对Mockery链式调用的返回值类型认知错误导致的:
Mockery::mock()、makePartial()这类初始化mock对象本身的方法,返回值确实是生成的模拟对象实例,可以链式调用同类初始化方法。shouldReceive()、with()、andReturn()这类配置方法调用期望的方法,返回值不是mock对象,而是Mockery\Expectation类的实例——这个类的作用是定义mock方法的匹配规则、返回值、调用次数约束,本身不具备你模拟的业务类的方法。
两种写法的差异本质是变量存储的值完全不同:
- 分写的逻辑:第一行把
makePartial()返回的mock实例赋值给$mock,第二行调用$mock->shouldReceive(123)时,返回的Expectation对象没有被赋值给任何变量,$mock里存的始终是合法的mock实例,后续调用setTime等业务方法自然正常。 - 错误链式写法的逻辑:PHP链式赋值取最后一个方法的返回值,
$mock最终存的是shouldReceive()返回的Expectation实例,你后续把这个Expectation对象当初始化好的mock用,调用setTime()方法时,Expectation类里根本不存在这个方法,就会抛出你看到的错误:
TypeError: call_user_func_array(): Argument #1 ($callback) must be a valid callback, class Mockery\Expectation does not have a method "setTime"
正确写法
推荐写法(分写,可读性最高,不容易出错)
$mock = Mockery::mock()->makePartial(); $mock->shouldReceive(123); // 后续正常调用mock的业务方法即可 $mock->setTime(time());
链式写法(如果必须写在同一组调用链里)
配置完所有期望规则后,调用Expectation类的getMock()方法拿回真正的mock实例再赋值:
$mock = Mockery::mock()->makePartial() ->shouldReceive(123) ->andReturn('mock_result') // 可继续链式配置期望:入参规则、返回值、调用次数等 ->getMock(); // 此时$mock是合法的模拟对象,可正常调用业务方法 $mock->setTime(time());
内容的提问来源于stack exchange,提问作者Artem Ivanov
相关产品推荐
相关产品推荐

