Ответ 1
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 (замыкание), с закрытием, определенным выше (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 будет считать его неудачным.
Ожидание в этом примере будет передано для закрытия any, которое передается в myclass::mymethod
, что, вероятно, недостаточно специфично. Вероятно, вам нужен более сложный тест, но основная идея.