laravel 嘲笑没有匹配的关闭处理程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22946306/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mockery no matching handler for closure
提问by Webnet
I can't figure out why I'm getting this error during this test. My test appears to be matching the rest of the code exactly. What am I overlooking?
我不明白为什么在这次测试中我会收到这个错误。我的测试似乎与代码的其余部分完全匹配。我在看什么?
In my test I have:
在我的测试中,我有:
$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']);
})
);
The error:
错误:
Mockery\Exception\NoMatchingExpectationException: No matching handler found for Mockery_4_Illuminate_Auth_Reminders_PasswordBroker::reset(array('email'=>'[email protected]','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 (
),
),
))
Part of my lack of understanding may have to do with the fact that I'm not sure what the Objects: array(....)
is that appears at the bottom of the error.
我缺乏理解的部分原因可能是因为我不确定Objects: array(....)
错误底部出现的是什么。
回答by Kryten
TL;DR: your closure argument to Mockery::on
needs to return true
or false
.
TL;DR:您的闭包参数Mockery::on
需要返回true
或false
。
The longer explanation:
更长的解释:
The problem is with your call to Mockery::on
. This method takes a closure (or other function) as an argument. That closure should return true or false, depending on whether the argument to the closure satisfies the test.
问题在于您对 的调用Mockery::on
。此方法将闭包(或其他函数)作为参数。该闭包应该返回 true 或 false,这取决于闭包的参数是否满足测试。
That was a rather confusing explanation, so I'll try an example :-)
这是一个相当令人困惑的解释,所以我会尝试一个例子:-)
Consider the following expectation:
考虑以下期望:
$mock = Mockery::mock("myclass");
$mock->shouldReceive("mymethod")
->with("myargument")
->once()
->andReturn("something");
This expectation will be met if the system under test (SUT) calls
如果被测系统 (SUT) 调用,则将满足此期望
$x = $myclass->mymethod("myargument");
and the value of $x
will be "something".
并且$x
will的值是“某物”。
Now the developers of Mockery realized that there are some expectations that they simply cannot meet. For example (and this is something that tripped me up for a while), a closure. It turns out that a closure in PHP is some kind of complicated internal resource, and even if you define two closures identically, they will not be the same. Consider:
现在,Mockery 的开发人员意识到有些期望是他们根本无法满足的。例如(这让我绊倒了一段时间),关闭。事实证明,PHP 中的闭包是某种复杂的内部资源,即使您定义相同的两个闭包,它们也不会相同。考虑:
$x = function($v){ echo $v; };
$y = function($v){ echo $v; };
echo $x==$y ? "True" : "False";
will echo the value "False". Why? From my limited understanding of the subject, it has something to do with the internal representation of closure objects in PHP. So, when you're mocking a method that requires a closure as an argument, there is no way to satisfy the expectation.
将回显值“False”。为什么?从我对这个主题的有限理解来看,它与 PHP 中闭包对象的内部表示有关。因此,当您模拟需要闭包作为参数的方法时,无法满足期望。
The Mockery::on()
method provides a way around this. Using this method, you can pass a (different) closure to Mockery that evaluates to true or false, depending on whether yourtests show that you have the right arguments. An example:
该Mockery::on()
方法提供了一种解决方法。使用此方法,您可以向 Mockery 传递一个(不同的)闭包,该闭包的计算结果为 true 或 false,具体取决于您的测试是否表明您拥有正确的参数。一个例子:
Imagine that myclass::mymethod
requires a closure as an argument. The following will always fail, regardless of what closure you pass to mymethod
in the SUT:
想象一下,这myclass::mymethod
需要一个闭包作为参数。无论您mymethod
在 SUT 中传递给哪个闭包,以下操作始终会失败:
$mock = Mockery::mock("myclass");
$mock->shouldReceive("mymethod")
->with(function($v){ echo $v; })
->once()
->andReturn("something");
This is because Mockery will compare the argument passed in the SUT (a closure) to the closure defined above (function($v){ echo $v; }
) and that test will fail, even if the two closures are identically defined.
这是因为 Mockery 会将 SUT(一个闭包)中传递的参数与上面定义的闭包 ( function($v){ echo $v; }
) 进行比较,即使这两个闭包定义相同,该测试也会失败。
Using Mockery::on()
, you can rewrite the test as follows:
使用Mockery::on()
,您可以按如下方式重写测试:
$mock = Mockery::mock("myclass");
$mock->shouldReceive("mymethod")
->with(Mockery::on(function($value){
return is_callable($value);
}))
->once()
->andReturn("something");
Now when Mockery evaluates the expectation, it will call the closure passed as the argument to Mockery::on()
. If it returns true
, Mockery will consider the expectation passed; if it returns false
, Mockery will consider it as having failed.
现在,当 Mockery 评估期望值时,它会调用作为参数传递给 的闭包Mockery::on()
。如果返回true
,Mockery 会认为期望通过了;如果它返回false
,Mockery 会认为它失败了。
The expectation in this example will pass for anyclosure that is passed to myclass::mymethod
, which is probably not specific enough. You probably want a more sophisticated test, but that's the basic idea.
此示例中的期望将传递给传递给 的任何闭包myclass::mymethod
,这可能不够具体。您可能想要更复杂的测试,但这是基本思想。
回答by Joel Harkes
If you are where like me not figuring out why it throws errors, you need to replace ->with()
into ->withArgs()
, when you have multiple function parameters.
如果你像我一样不知道为什么会抛出错误,当你有多个函数参数时,你需要替换->with()
into ->withArgs()
。
working version
工作版本
$mock->shouldReceive('functionWithMoreParams')->withArgs(fn($arg1, $arg2) => true);
Throwing error
投掷错误
$mock->shouldReceive('functionWithMoreParams')->with(fn($$arg1, $arg2) => true);