Издевательство нет соответствующего обработчика для закрытия
Я не могу понять, почему я получаю эту ошибку во время этого теста. Мой тест, похоже, точно соответствует остальной части кода. Что я упускаю из виду?
В моем тесте у меня есть:
$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(....)
является то, что появляется в нижней части ошибки.
Ответы - Издевательство нет соответствующего обработчика для закрытия / Mockery no matching handler for closure

09.04.2014 01:44:36
TL; DR: ваш аргумент закрытия к Mockery::on
должен вернуть true
или false
.
Более длинное объяснение:
Проблема в вашем призыве к Mockery::on
. Этот метод принимает замыкание (или другую функцию) в качестве аргумента. Это замыкание должно возвращать true или false, в зависимости от того, удовлетворяет ли аргумент замыкания тесту.
Это было довольно запутанное объяснение, поэтому я попробую пример :-)
Рассмотрим следующее ожидание:
$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, которое оценивается как true или false, в зависимости от того, показывают ли ваши тесты, что у вас есть правильные аргументы. Образец:
Представьте, что myclass::mymethod
требует закрытия в качестве аргумента. Следующее всегда будет неудачным, независимо от того, какое закрытие вы передаете mymethod
в SUT:
$mock = Mockery::mock("myclass");
$mock->shouldReceive("mymethod")
->with(function($v){ echo $v; })
->once()
->andReturn("something");
Это происходит потому, что Mockery будет сравнивать аргумент, переданный в SUT (замыкание A), с замыканием, определенным выше (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
, издевательство будет рассматривать ожидание прошло; если она возвращает false
, издевательство будет рассматривать его как ошибочный.
Ожидание в этом примере пройдет для любого закрытия, которое передается myclass::mymethod
, который, вероятно, недостаточно специфичен. Вы, вероятно, хотите более сложный тест, но это основная идея.



