2012-09-26 32 views
16

Soy nuevo en pruebas unitarias y PHPUnit.Método no definido en el objeto simulado que implementa una interfaz determinada en PHPUnit?

Necesito un simulacro, en el que tengo un control total, implementando la interfaz ConfigurationInterface. El sujeto de prueba es el objeto ReportEventParamConverter y la prueba debe verificar la interacción entre mi objeto y la interfaz.

ReportEventParamConverter objeto (en este caso simplificado):

class ReportEventParamConverter implements ParamConverterInterface 
{ 
    /** 
    * @param Request $request 
    * @param ConfigurationInterface $configuration 
    */ 
    function apply(Request $request, ConfigurationInterface $configuration) 
    { 
     $request->attributes->set($configuration->getName(), $reportEvent); 
    } 

    /** 
    * @param ConfigurationInterface $configuration 
    * @return bool 
    */ 
    function supports(ConfigurationInterface $configuration) 
    { 
     return 'My\Namespaced\Class' === $configuration->getClass(); 
    } 
} 

Y esta es la forma en que estoy tratando de burlarse de la interfaz:

$cls = 'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface'; 
$mock = $this->getMock($mockCls); 

necesito para simular los valores devueltos para dos métodos: getClass() y getName(). Por ejemplo:

$mock->expects($this->any()) 
    ->method('getClass') 
    ->will($this->returnValue('Some\Other\Class')) 
; 

cuando creo un nuevo método ReportEventParamConverter y la prueba supports(), me sale el siguiente error PHPUnit:

Fatal error: Call to undefined method Mock_ConfigurationInterface_21e9dccf::getClass().

$converter = new ReportEventParamConverter(); 
$this->assertFalse($converter->supports($mock)); 
+0

¿El 'ParamConverterInterface' tiene el método' getClass() '? – hakre

+0

@hakra ¿eso importa? – gremo

+0

Responda la pregunta para agregar más información a su pregunta. Eso sería importante. Aparte de eso, sería mi primera suposición de por qué el simulacro no tiene esa función. Entonces algo de depuración básica. – hakre

Respuesta

18

es porque no hay ninguna declaración de método "getClass" en ConfigurationInterface. La única declaración en esta interfaz es el método "getAliasName".

Todo lo que necesita es saber qué métodos de la maqueta se le Stubing:

$cls = 'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface'; 
$mock = $this->getMock($mockCls, array('getClass', 'getAliasName')); 

en cuenta que no hay ninguna declaración "getClass" pero se puede Stub existente/no fingida también. Para ello se puede burlarse de él:

$mock->expects($this->any()) 
    ->method('getClass') 
    ->will($this->returnValue('Some\Other\Class')); 

Pero en addtion necesita para burlarse método "getAliasName", así como el tiempo que es el método de interfaz o un resumen y tiene que ser "aplicado". Ejemplo:

$mock->expects($this->any()) 
    ->method('getAliasName') 
    ->will($this->returnValue('SomeValue')); 
+0

Entonces, si los métodos no existen en la clase original debe declararse en la llamada 'getMock()'? Si el método existe, entonces no es necesario? – gremo

+3

Siempre debe decirle que se burle de qué métodos va a fallar. Si no especifica eso, el simulan que cortarán todos los métodos de la clase (por ejemplo, si especificas solo un método methodA, $ mock = $ this-> getMock ('Class', array ('methodA')), el simulacro asume que solo te burlas methodA, y cuando llamas a otro método: $ mock-> methodB(), se ejecuta el método "real" de "Class") – Cyprian

+0

¡Gracias! Funciona ahora. – gremo

12

La respuesta de Cyprian me ayudó, pero hay que tener en cuenta. Puede simular clases que no existen, y PHPUnit no se quejará. Por lo que podría hacer

$mock = $this->getMock('SomeClassThatDoesntExistOrIsMisspelledOrPerhapsYouForgotToRequire'); 

Esto significa que si ConfigurationInterface no existe en ese punto durante el tiempo de ejecución, todavía tendrá un mensaje como

Fatal error: Call to undefined method Mock_ConfigurationInterface_21e9dccf::getClass().

Si estás seguro de que el método realmente existe en la clase, entonces el problema probable es que la clase en sí misma no existe (porque no la has requerido, o la has escrito mal, etc.).


La OP está utilizando una interfaz.Se le informa que debe llamar getMock sin especificar la lista de métodos para anular, o si lo hace, debe pasar array(), o pasar todos los nombres de los métodos, o tendrá que obtener un error como el siguiente:

PHP Fatal error: Class Mock_HttpRequest_a7aa9ffd contains 4 abstract methods and must therefore be declared abstract or implement the remaining methods (HttpRequest::setOption, HttpRequest::execute, HttpRequest::getInfo, ...)

+2

Gracias por mencionar esto, de hecho era una clase perdida que era causándome problemas. – ChiperSoft

+0

Gracias. H y el mismo problema – Mantas

+0

Experimenté esto mientras me burlaba de una biblioteca externa que 'requería' en la clase bajo prueba, pero no se ajustaba al autocargador. –

1

La advertencia de Tyler Collier es justa, pero no contiene un fragmento de código sobre cómo codificarla. Tenga en cuenta que esto es muy desagradable y en su lugar debe arreglar la interfaz. Con esa advertencia agregada:

$methods = array_map(function (\ReflectionMethod $m) { return $m->getName();}, (new \ReflectionClass($interface))->getMethods()); 
$methods[] = $missing_method; 
$mock = $this->getMock($interface, $methods); 
Cuestiones relacionadas