嘲笑没有匹配的关闭处理程序

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 的闭包参数需要返回truefalse

更长的解释

问题在于您致电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::mymethodany 闭包,这可能不够具体。您可能想要更复杂的测试,但这是基本理念。

【讨论】:

/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画素描人像

MessageMapping 处理程序 - 没有匹配的方法

在没有 Dispose 事件处理程序的情况下处理应用程序关闭事件

iOS 问题。未找到匹配的代码签名身份。有没有搞错? [关闭]

访问 webhook URL 时出现错误“操作错误:没有匹配的意图处理程序:null”

没有任何事先设置的硬件中断如何触发软件处理程序[关闭]