嘲笑没有匹配的处理程序进行闭包

2022-08-30 20:22:25

我无法弄清楚为什么在此测试期间收到此错误。我的测试似乎与代码的其余部分完全匹配。我忽略了什么?

在我的测试中,我有:

    $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::ontruefalse

更长的解释

问题出在您调用 .此方法采用闭包(或其他函数)作为参数。该闭包应返回 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,该闭包的计算结果为 true 或 false,具体取决于您的测试是否显示您具有正确的参数。例如:Mockery::on()

想象一下,这需要一个闭包作为参数。无论您在 SUT 中传递到哪种闭包,以下操作都将始终失败:myclass::mymethodmymethod

$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将认为期望已通过;如果它返回,Mockery会认为它失败了。Mockery::on()truefalse

此示例中的期望将传递给 的任何闭包传递,这可能不够具体。你可能想要一个更复杂的测试,但这是基本的想法。myclass::mymethod


答案 2

如果你像我一样没有弄清楚为什么它会抛出错误,当你有多个函数参数时,你需要替换成。->with()->withArgs()

工作版本

$mock->shouldReceive('functionWithMoreParams')->withArgs(fn($arg1, $arg2) => true);

抛出错误

$mock->shouldReceive('functionWithMoreParams')->with(fn($$arg1, $arg2) => true);


推荐