我无法弄清楚为什么在此测试期间出现此错误。我的测试似乎与其余代码完全匹配。我在俯视什么?

在我的测试中,我有:

    $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'=>'[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 (
    ),
  ),
))

我缺乏理解的部分原因可能是由于我不确定出现在错误底部的Objects: array(....)是什么。

最佳答案

TL; DR :您对Mockery::on的闭包参数需要返回truefalse

更长的解释:

问题出在您对Mockery::on的调用上。此方法将闭包(或其他函数)作为参数。该闭包应该返回true或false,这取决于闭包的参数是否满足测试。

这是一个相当困惑的解释,所以我将尝试一个示例:-)

考虑以下期望:

$mock = Mockery::mock("myclass");
$mock->shouldReceive("mymethod")
    ->with("myargument")
    ->once()
    ->andReturn("something");

如果被测系统(SUT)调用,将满足此期望
$x = $myclass->mymethod("myargument");

并且$x的值将为“something”。

现在,Mockery的开发人员意识到有些期望是他们根本无法满足的。例如(这使我绊了一会儿),关闭。事实证明,PHP中的闭包是某种复杂的内部资源,即使您完全相同地定义两个闭包,它们也将是不同的。考虑:
$x = function($v){ echo $v; };
$y = function($v){ echo $v; };

echo $x==$y ? "True" : "False";

将回显值“False”。为什么?从我对该主题的有限了解来看,它与PHP中闭包对象的内部表示形式有关。因此,当您模拟需要闭包作为参数的方法时,无法满足的期望。
Mockery::on()方法提供了解决此问题的方法。使用此方法,可以将(不同的)闭包传递给Mockery,该闭包的评估结果为true或false,具体取决于测试是否表明您具有正确的参数。一个例子:

假设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的任何闭包传递给,这可能不够具体。您可能需要更复杂的测试,但这是基本思想。

10-08 01:08