PHPUnit "Мошеннический метод не существует."при использовании $ mock-> Ожидается ($ this-> at (...)) - PullRequest
38 голосов
/ 30 июля 2010

Я столкнулся со странной проблемой с фиктивными объектами PHPUnit. У меня есть метод, который должен вызываться дважды, поэтому я использую сопоставление at. Это работает в первый раз, когда вызывается метод, но по какой-то причине, во второй раз, когда он вызывается, я получаю «Заблокированный метод не существует». Я использовал "at" matcher раньше и никогда не сталкивался с этим.

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

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.

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

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

Спасибо!

Ответы [ 7 ]

42 голосов
/ 06 августа 2010

В итоге проблема заключалась в том, как я понял, что "at" matcher работает. Кроме того, мой пример не был дословным, как в моем модульном тесте. Я думал, что счетчик совпадений 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"));
    }

}
16 голосов
/ 17 октября 2012

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

Это подняло ошибку

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

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

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

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

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

5 голосов
/ 26 октября 2012

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

3 голосов
/ 11 марта 2014

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

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

Для меня, насколько я знаю, с моим собственным кодом, я должен был использовать 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's what was passed: $arg");
    })
);
1 голос
/ 30 июля 2010

Насколько я могу судить по демо-коду, должно работать.Я создал рабочий пример, если вы используете старую версию 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)
0 голосов
/ 24 октября 2018

Может быть не тогда, когда был задан вопрос, однако сегодня документация четко определяет, как следует использовать at, и я цитирую

Примечание
Параметр $ index для at() matcher ссылается на индекс, начиная с нуля, во всех вызовах методов для данного фиктивного объекта.Будьте осторожны при использовании этого сопоставителя, так как это может привести к хрупким испытаниям, которые слишком тесно связаны с конкретными деталями реализации.

0 голосов
/ 30 июля 2010

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

...