2008-11-10 11 views
75

¿Cuál es la manera de evitar que phpunit tenga que llamar al constructor para obtener un objeto simulado? De lo contrario, se necesita un objeto de burla como argumento del constructor, otra para que la API etc. parece ser así:phpunit evitar argumentos del constructor para el simulacro

getMock($className, $methods = array(), array $arguments = array(), 
     $mockClassName = '', $callOriginalConstructor = TRUE, 
     $callOriginalClone = TRUE, $callAutoload = TRUE) 

no consigo que funcione. Todavía se queja del argumento constructor, incluso con $callOriginalConstructor establecido en falso.

Solo tengo un objeto en el constructor y es una inyección de dependencia. Entonces no creo que tenga un problema de diseño allí.

Respuesta

1

Quizás necesite crear un stub para pasar como el argumento del constructor. Entonces puedes romper esa cadena de objetos falsos.

+1

Podría por favor compartir más información –

0

PHPUnit está diseñado para llamar al constructor en objetos simulados; para evitar esto, usted debe ya sea:

  1. inyectar un objeto de burla como una dependencia en el objeto que está teniendo problemas para burlarse
  2. crear una clase de prueba que extiende la clase que usted está tratando de llamar que no lo hace llamar al constructor padre
40

Aquí van:

// Get a Mock Soap Client object to work with. 
    $classToMock = 'SoapClient'; 
    $methodsToMock = array('__getFunctions'); 
    $mockConstructorParams = array('fake wsdl url', array()); 
    $mockClassName = 'MyMockSoapClient'; 
    $callMockConstructor = false; 
    $mockSoapClient = $this->getMock($classToMock, 
            $methodsToMock, 
            $mockConstructorParams, 
            $mockClassName, 
            $callMockConstructor); 
+0

Esto parece ser casi lo que quiero. Quiero llamar al getMock con solo clase para burlarse y al $ callMockConstructor. ¿Cómo? algo como esto: $ this-> getMock ($ classToMock, $ callMockConstructor). Lo único que se me ocurre es entrar en la fuente de PHPUnit y cambiarla a default = false. – Gutzofter

+1

Cambié el valor predeterminado a falso en testcase.php. Creerías que se configuraría como falso por defecto. Burlarse de un constructor parece muy extraño – Gutzofter

+0

OBTW, ¡Gracias! – Gutzofter

121

se puede utilizar en lugar de sólo getMockBuildergetMock:

$mock = $this->getMockBuilder('class_name') 
    ->disableOriginalConstructor() 
    ->getMock(); 

véase la sección sobre "Test Doubles" en PHPUnit's documentation para más detalles.

Aunque puede hacer esto, es mucho mejor no necesitarlo. Puedes refactorizar tu código para que, en lugar de una clase concreta (con un constructor) que deba ser inyectada, solo dependas de una interfaz. Esto significa que puede simular o resguardar la interfaz sin tener que decirle a PHPUnit que modifique el comportamiento del constructor.

+0

Esto funciona muy bien para mí. Sin embargo, debería ser el ejemplo 10.3. Traté de editar la publicación, pero SO lo rechazó por ser una edición demasiado corta. – Matthew

+0

Gracias @Lytithwyn. Actualizado la respuesta. – dave1010

+0

funciona para mí también. ¡Gracias! – Jeune

3

Como una adición, quería adjuntar llamadas expects() a mi objeto simulado y luego llamar al constructor. En PHPUnit 3.7.14, el objeto que se devuelve al llamar al disableOriginalConstructor() es literalmente un objeto.

// Use a trick to create a new object of a class 
// without invoking its constructor. 
$object = unserialize(
sprintf('O:%d:"%s":0:{}', strlen($className), $className) 

Por desgracia, en PHP 5.4 hay una nueva opción, que no están utilizando:

ReflectionClass::newInstanceWithoutConstructor

Dado que esto no estaba disponible, que tenía que reflejar manualmente la clase y luego invocar el constructor

$mock = $this->getMockBuilder('class_name') 
    ->disableOriginalConstructor() 
    ->getMock(); 

$mock->expect($this->once()) 
    ->method('functionCallFromConstructor') 
    ->with($this->equalTo('someValue')); 

$reflectedClass = new ReflectionClass('class_name'); 
$constructor = $reflectedClass->getConstructor(); 
$constructor->invoke($mock); 

Tenga en cuenta, si es functionCallFromConstructprotected, que tiene específicamente para utilizar setMethods() de manera que puede ser burlado el método protegido. Ejemplo:

$mock->setMethods(array('functionCallFromConstructor')); 

setMethods() debe ser llamado antes de la llamada expect(). Personalmente, encadenó esto después de disableOriginalConstructor() pero antes de getMock().

1

Como alternativa, puede agregar un parámetro a getMock para evitar la llamada del constructor predeterminado.

$mock = $this->getMock(class_name, methods = array(), args = array(), 
     mockClassName = '', callOriginalConstructor = FALSE); 

Sin embargo, creo que la respuesta de dave1010 ve mejor, esto es sólo por el bien de la integridad.

Cuestiones relacionadas