Издевательство нет соответствующего обработчика для закрытия

Издевательство нет соответствующего обработчика для закрытия

08.04.2014 11:20:01 Просмотров 29 Источник

Я не могу понять, почему я получаю эту ошибку во время этого теста. Мой тест, похоже, точно соответствует остальной части кода. Что я упускаю из виду?

В моем тесте у меня есть:

    $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

Является ответом!
Kryten

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, который, вероятно, недостаточно специфичен. Вы, вероятно, хотите более сложный тест, но это основная идея.

https://stackoverflow.com/questions/22946306/mockery-no-matching-handler-for-closure/22948810#comment35037374_22948810
/рукалицо .... Я знаю, что он должен вернуть истину или ложь и полностью исключить его. Вы совершенно правы! Спасибо за подробное объяснение, +1!
https://stackoverflow.com/questions/22946306/mockery-no-matching-handler-for-closure/22948810#comment35038013_22948810
В последние недели я уже несколько раз сталкивался с этой проблемой. Я думаю, что закажу это, чтобы мне не пришлось снова и снова его решать. :-)
https://stackoverflow.com/questions/22946306/mockery-no-matching-handler-for-closure/22948810#comment50699413_22948810
- Но почему? Исходя из моего ограниченного понимания предмета, это имеет какое-то отношение к внутреннему представлению объектов закрытия в PHP"
https://stackoverflow.com/questions/22946306/mockery-no-matching-handler-for-closure/22948810#comment104272917_22948810
Спасибо, ты спас меня! Для таких манекенов, как я, используйте один "Mock:: on" за аргумент!
Закрыть X