PHPUnit "El método burlado no existe" cuando se usa $ simulacros-> espera($ this-> at(...))
unit-testing mocking (6)
Me encontré con un problema extraño con PHPUnit simulacro de objetos. Tengo un método que debería llamarse dos veces, entonces estoy usando el matcher "at". Esto funciona por primera vez cuando se llama al método, pero por alguna razón, la segunda vez que se llama, obtengo "El método burlado no existe". He usado el matcher "at" antes y nunca me he encontrado con esto.
Mi código se ve algo así como:
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));
}
...
}
Cuando realizo la prueba, obtengo:
Expectation failed for method name is equal to <string:exists> when invoked at sequence index 1.
Mocked method does not exist.
Si elimino el segundo comparador, no obtengo el error.
¿Alguien ha topado con esto antes?
¡Gracias!
¿Estás seguro de que incluiste MyClass en tu prueba? He tenido algunos errores de método no definidos al burlar una clase / interfaz sin incluirla.
El problema terminó con la forma en que entendí el matcher "at" para trabajar. Además, mi ejemplo no era literalmente como está en mi prueba unitaria. Pensé que el contador de coincidencias "at" funcionaba por consulta, donde realmente funciona por instancia de objeto.
Ejemplo:
class MyClass {
public function exists($foo) {
return false;
}
public function find($foo) {
return $foo;
}
}
Incorrecto:
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"));
}
}
Correcto:
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"));
}
}
Esta es una frase desafortunada del mensaje de error de PHPUnit.
Verifique el orden de sus llamadas, como las respuestas de @ rr.
Para mí, hasta donde yo sé, con mi propio código, debería estar usando at(0)
y at(1)
respectivamente, pero no fue hasta que usé at(2)
y at(3)
que funcionó. (Estoy usando la burla de la sesión en CakePHP.)
La mejor manera de verificar el pedido es "entrar" en el método llamado y verificar lo que pasó. Puedes hacer eso así:
$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");
})
);
FYI, no estoy seguro si está relacionado, pero me encontré con lo mismo, pero no con el método $this->at()
, para mí fue el método $this->never()
.
Esto levantó el error
$mock->expects($this->never())
->method(''exists'')
->with(''arg'');
Esto corrigió el error
$mock->expects($this->never())
->method(''exists'');
Hizo lo mismo cuando usó el método $this->exactly(0)
.
Espero que esto ayude a alguien.
Intenta cambiar $this->at(1)
a $this->at(2)
Por lo que puedo decir del código Demo, debería funcionar. Produje un ejemplo de trabajo en caso de que esté ejecutando una versión anterior de PHPUnit y quiera verificarlo de esa manera si también le funciona.
En caso de que eso no ayude, ¿podría proporcionar un poco más de código (al mejor ejecutable)? :)
<?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;
}
}
impresión
phpunit MyTest.php
PHPUnit 3.4.15 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 4.25Mb
OK (1 test, 3 assertions)