嘲笑没有匹配的关闭处理程序
Posted
技术标签:
【中文标题】嘲笑没有匹配的关闭处理程序【英文标题】:Mockery no matching handler for closure 【发布时间】:2014-05-21 16:42:48 【问题描述】:我无法弄清楚为什么在此测试期间会出现此错误。我的测试似乎与其余代码完全匹配。我忽略了什么?
在我的测试中,我有:
$passwordBroker = m::mock('Illuminate\Auth\Reminders\PasswordBroker');
$passwordBroker->shouldReceive('reset')
->once()
->with(
$this->resetAttributes,
m::on(function (\Closure $closure)
$this->entity
->shouldReceive('setAttribute')
->once()
->with('password', $this->resetAttributes['password']);
$this->entity
->shouldReceive('getAttributes')
->once()
->andReturn($this->resetAttributes);
$closure($this->entity, $this->resetAttributes['password']);
)
);
错误:
Mockery\Exception\NoMatchingExpectationException: No matching handler found for Mockery_4_Illuminate_Auth_Reminders_PasswordBroker::reset(array('email'=>'test@email.com','password'=>'myTestPassword','password_confirmation'=>'myTestPassword',), Closure). Either the method was unexpected or its arguments matched no expected argument list for this method
Objects: (array (
'Closure' =>
array (
'class' => 'Closure',
'properties' =>
array (
),
'getters' =>
array (
),
),
))
我不理解的部分原因可能与我不确定错误底部出现的Objects: array(....)
是什么有关。
【问题讨论】:
【参考方案1】:TL;DR:您对Mockery::on
的闭包参数需要返回true
或false
。
更长的解释:
问题在于您致电Mockery::on
。此方法将闭包(或其他函数)作为参数。该闭包应该返回真或假,具体取决于闭包的参数是否满足测试。
这是一个相当混乱的解释,所以我将尝试一个示例:-)
考虑以下期望:
$mock = Mockery::mock("myclass");
$mock->shouldReceive("mymethod")
->with("myargument")
->once()
->andReturn("something");
如果被测系统 (SUT) 调用,就会满足这个期望
$x = $myclass->mymethod("myargument");
$x
的值将是“某物”。
现在,Mockery 的开发人员意识到有些期望是他们根本无法满足的。例如(这是让我绊倒了一段时间的事情),关闭。事实证明,php 中的闭包是某种复杂的内部资源,即使您定义相同的两个闭包,它们也不会相同。考虑:
$x = function($v) echo $v; ;
$y = function($v) echo $v; ;
echo $x==$y ? "True" : "False";
将回显值“False”。为什么?从我对这个主题的有限理解来看,它与 PHP 中闭包对象的内部表示有关。因此,当您模拟需要闭包作为参数的方法时,无法满足期望。
Mockery::on()
方法提供了一种解决方法。使用此方法,您可以将(不同的)闭包传递给 Mockery,该闭包的计算结果为真或假,具体取决于 您的 测试是否显示您有正确的参数。一个例子:
想象myclass::mymethod
需要一个闭包作为参数。无论您在 SUT 中将什么闭包传递给 mymethod
,以下操作总是会失败:
$mock = Mockery::mock("myclass");
$mock->shouldReceive("mymethod")
->with(function($v) echo $v; )
->once()
->andReturn("something");
这是因为 Mockery 会将 SUT(闭包)中传递的参数与上面定义的闭包 (function($v) echo $v;
) 进行比较,即使两个闭包的定义相同,该测试也会失败。
使用Mockery::on()
,可以重写测试如下:
$mock = Mockery::mock("myclass");
$mock->shouldReceive("mymethod")
->with(Mockery::on(function($value)
return is_callable($value);
))
->once()
->andReturn("something");
现在,当 Mockery 评估期望时,它将调用作为参数传递给 Mockery::on()
的闭包。如果返回true
,则Mockery会认为期望通过;如果返回false
,Mockery 会认为它失败了。
本示例中的期望将传递给传递给myclass::mymethod
的any 闭包,这可能不够具体。您可能想要更复杂的测试,但这是基本理念。
【讨论】:
/facepalm .... 我知道它需要返回 true 或 false 并完全排除它。你完全正确!感谢您的详细解释,+1! 最近几周我多次被同样的问题困扰。我想我会把它加入书签,这样我就不必再重新解决它了:-) “为什么?从我对这个主题的有限理解来看,它与PHP中闭包对象的内部表示有关” 谢谢,你救了我!对于像我这样的傻瓜,每个参数都需要一个“Mock::on”! 非常感谢关闭修复!【参考方案2】:如果您像我一样不知道为什么会抛出错误,那么当您有多个函数参数时,您需要将 ->with()
替换为 ->withArgs()
。
工作版本
$mock->shouldReceive('functionWithMoreParams')->withArgs(fn($arg1, $arg2) => true);
投掷错误
$mock->shouldReceive('functionWithMoreParams')->with(fn($$arg1, $arg2) => true);
【讨论】:
以上是关于嘲笑没有匹配的关闭处理程序的主要内容,如果未能解决你的问题,请参考以下文章
女朋友嘲笑我没有艺术气息,我不服!!一气之下我用python画素描人像
在没有 Dispose 事件处理程序的情况下处理应用程序关闭事件
iOS 问题。未找到匹配的代码签名身份。有没有搞错? [关闭]