2009-11-05 22 views
6

Estoy tratando de probar si se llama a un método protegido en una interfaz pública.Probando si se llamó a un método protegido

<?php 
abstract class SomeClassAbstract 
{ 
    abstract public foo(); 

    public function doStuff() 
    {  
     $this->_protectedMethod(); 
    } 

    protected function _protectedMethod(); 
    { 
     // implementation is irrelevant 
    } 
} 

<?php 
class MyTest extends PHPUnit_Framework_TestCase 
{ 
    public function testCalled() 
    { 
     $mock = $this->getMockForAbstractClass('SomeClass'); 
     $mock->expects($this->once()) 
      ->method('_protectedMethod'); 

     $mock->doStuff(); 
    } 
} 

Sé que se llama correctamente, pero PHPUnit dice que nunca se llamó.

Lo mismo sucede cuando pruebo la inversa, cuando un método es Nunca llamada:

<?php 
abstract class AnotherClassAbstract 
{ 
    abstract public foo(); 

    public function doAnotherStuff() 
    {  
     $this->_loadCache(); 
    } 

    protected function _loadCache(); 
    { 
     // implementation is irrelevant 
    } 
} 

<?php 
class MyTest extends PHPUnit_Framework_TestCase 
{ 
    public function testCalled() 
    { 
     $mock = $this->getMockForAbstractClass('AnotherClass'); 
     $mock->expects($this->once()) 
      ->method('_loadCache'); 

     $mock->doAnotherStuff(); 
    } 
} 

El método se llama, pero PHPUnit dice que no lo es.

¿Qué estoy haciendo mal?

Editar I había't declarar mis métodos con dos puntos dobles, que era sólo para denotar que era un método público (interfaz). Actualizado a declaraciones de clases/métodos completos.

Editar 2 que debería haber dicho que estoy probando algunas implementaciones del método en una clase abstracta (editado el código para reflejar esto). Como no puedo crear una instancia de la clase, ¿cómo puedo probar esto?

Estoy pensando en crear un SomeClassSimple extendiendo SomeClassAbstract y probando este en su lugar. ¿Es el enfoque correcto?

Respuesta

11

En la versión de PHPUnit que tengo, la clase PHPUnit_Framework_MockObject_Mock usa PHP get_class_methods para determinar la interfaz del objeto que se está burlando. get_class_methods seleccionará solo los métodos públicos, no los privados o los protegidos.

Esto concuerda con el espíritu de las pruebas de la unidad xUnit. Considere el ejemplo de los documentos PHPUnit sobre cómo usar Mock Objects. Allí, el SUT es Subject, que tiene un método protegido notify. El método que se está probando, sin embargo, es doSomething. Teniendo en cuenta Subject como una caja negra, no nos importan los detalles de cómo se implementa. Nos importa, sin embargo, sobre su comportamiento . Específicamente, requerimos que cuando llamemos al doSomething, se llame al método update de cualquier observador adjunto. Así que nos burlamos del objeto de terceros Observer, y configuramos la expectativa de que se llamará a su método update. Tenga en cuenta que, aunque se aplica el método protegido notify, no se menciona explícitamente en la prueba. Eso nos da la libertad de cambiar la implementación cuando queramos, siempre y cuando se preserve el comportamiento.

Volviendo a su ejemplo.

class MyTest extends PHPUnit_Framework_TestCase 
{ 
    public function testCalled() 
    { 
    $mock = $this->getMock('SomeClass'); 
    $mock->expects($this->once()) 
     ->method('_protectedMethod'); 

    $mock->doStuff(); 
    } 
} 

En este caso, el método de testCalled crea ninguna instancia de la prueba del sistema Bajo (SUT), lo que sería SomeClass. La versión de doStuff en el simulacro de SomeClass no hace nada. En particular, no llama al _protectedMethod.

+0

Gracias Ewan, tienes razón.Por supuesto, si se trata de un objeto simulado, no tiene la implementación del método. Qué tonto yo. Marcaré tu respuesta como correcta. Si puedes, por favor, mira mi segunda edición. –

+0

Entonces, lo que intento probar es la implementación, no el comportamiento, ¿no? Es un poco más claro para mí, gracias. –

+2

La prueba de unidad es, creo, más de un arte de lo que parece. Lo aprecié más después de leer Patrones de prueba xUnit: Refactoring Test Code por Gerard Meszaros. A su vez, el libro fue una fuerte recomendación de Sebastian Bergmann, el autor de PHPUnit. –

4

Parece que sólo hay que contar PHPUnit que desea burlarse de esa función, es decir .:

$mock = $this->getMock('SomeClass', 
         array('_protectedMethod')); 
$mock->expects($this->once()) 
    ->method('_protectedMethod'); 

$mock->doStuff(); 
Cuestiones relacionadas