Подтвердить что ты не робот

PHPUnit "Мошеннический метод не существует". при использовании $mock-> expects ($ this-> at (...))

У меня возникла странная проблема с объектами макета PHPUnit. У меня есть метод, который следует вызывать дважды, поэтому я использую "at" matcher. Это работает в первый раз, когда метод вызывается, но по какой-то причине, во второй раз, когда он вызывался, я получаю "Mocked method does not exist.". Раньше я использовал совпадение "at" и никогда не сталкивался с этим.

Мой код выглядит примерно так:

class MyTest extends PHPUnit_Framework_TestCase
{
    ...

    public function testThis()
    {
        $mock = $this->getMock('MyClass', array('exists', 'another_method', '...'));
        $mock->expects($this->at(0))
             ->method('exists')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue(true));

        $mock->expects($this->at(1))
             ->method('exists')
             ->with($this->equalTo('bar'))
             ->will($this->returnValue(false));
    }

    ...
}

Когда я запускаю тест, я получаю:

Expectation failed for method name is equal to <string:exists> when invoked at sequence index 1.
Mocked method does not exist.

Если я удаляю второй матчи, я не получаю ошибку.

Кто-нибудь сталкивался с этим раньше?

Спасибо!

4b9b3361

Ответ 1

Проблема закончилась тем, что я понял, что "at" подходит для работы. Кроме того, мой пример не был дословным, как он находится в моем unit test. Я думал, что счетчик совпадений "at" работал на основе каждого запроса, где он действительно работает на основе каждого объекта.

Пример:

class MyClass {

    public function exists($foo) {
        return false;
    }

    public function find($foo) {
        return $foo;
    }
}

Неправильно:

class MyTest extends PHPUnit_Framework_TestCase
{

    public function testThis()
    {
        $mock = $this->getMock('MyClass');
        $mock->expects($this->at(0))
             ->method('exists')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue(true));

        $mock->expects($this->at(0))
             ->method('find')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue('foo'));

        $mock->expects($this->at(1))
             ->method('exists')
             ->with($this->equalTo('bar'))
             ->will($this->returnValue(false));

        $this->assertTrue($mock->exists("foo"));
        $this->assertEquals('foo', $mock->find('foo'));
        $this->assertFalse($mock->exists("bar"));
    }

}

Правильно:

class MyTest extends PHPUnit_Framework_TestCase
{

    public function testThis()
    {
        $mock = $this->getMock('MyClass');
        $mock->expects($this->at(0))
             ->method('exists')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue(true));

        $mock->expects($this->at(1))
             ->method('find')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue('foo'));

        $mock->expects($this->at(2))
             ->method('exists')
             ->with($this->equalTo('bar'))
             ->will($this->returnValue(false));

        $this->assertTrue($mock->exists("foo"));
        $this->assertEquals('foo', $mock->find('foo'));
        $this->assertFalse($mock->exists("bar"));
    }

}

Ответ 2

FYI, Не уверен, что это связано, но я столкнулся с тем же, но не с методом $this->at(), для меня это был метод $this->never().

Это привело к ошибке

$mock->expects($this->never())
    ->method('exists')
    ->with('arg');

Исправлена ​​ошибка

$mock->expects($this->never())
    ->method('exists');  

Проделал то же самое при использовании метода $this->exactly(0).

Надеюсь, что это поможет кому-то.

Ответ 3

Попробуйте изменить $this->at(1) на $this->at(2)

Ответ 4

Это печальная формулировка сообщения об ошибке с помощью PHPUnit.

Дважды проверьте порядок ваших вызовов, например, @rr answer.

Для меня, насколько я знаю, с моим собственным кодом, я должен использовать at(0) и at(1) соответственно, но это было только до тех пор, пока я не использовал at(2) и at(3) вместо этого, чтобы он работал. (Я использую сессию, издевающуюся над CakePHP.)

Лучший способ проверить порядок - получить "в" вызываемый метод и проверить, что прошло. Вы можете сделать это вот так:

$cakePost = $this->getMock('CakePost');
$cakePost->expects($this->once())
->method('post')
->with(
    // Add a line like this for each arg passed
    $this->callback(function($arg) {
        debug("Here what was passed: $arg");
    })
);

Ответ 5

Насколько я могу судить по демо-коду, он должен работать. Я подготовил рабочий пример, если вы используете более раннюю версию PHPUnit и хотите проверить этот способ, если он работает и для вас.

В случае, если это не поможет, возможно, вы могли бы предоставить немного больше (в лучшем случае исполняемый) код?:)

<?php

class MyTest extends PHPUnit_Framework_TestCase
{

    public function testThis()
    {
        $mock = $this->getMock('MyClass');
        $mock->expects($this->at(0))
             ->method('exists')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue(true));

        $mock->expects($this->at(1))
             ->method('exists')
             ->with($this->equalTo('bar'))
             ->will($this->returnValue(false));

        $this->assertTrue($mock->exists("foo"));
        $this->assertFalse($mock->exists("bar"));
    }

}

class MyClass {

    public function exists($foo) {
        return false;
    }
}

Печать

phpunit MyTest.php
PHPUnit 3.4.15 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 4.25Mb

OK (1 test, 3 assertions)

Ответ 6

Вы уверены, что включили MyClass в свой тест? У меня были некоторые ошибки метода undefined при смехе класса/интерфейса без его включения.