2011-12-23 20 views
12

Escribo una clase que heredará una interfaz. El código del cliente se escribirá para esa interfaz y la clase escrita para soportarlo. La idea es que más adelante escribiré otras clases para esa interfaz, y los objetos de esas dos clases diferentes deberían ser completamente intercambiables. En lugar de escribir una clase de prueba para esa primera clase, quiero escribir una para la interfaz.PHPUnit: escribir una clase de prueba para una interfaz y probar objetos usando una fábrica

Mi plan era escribir una clase de prueba que tomara un objeto de fábrica para el constructor (inyección de dependencia) y usar la fábrica para crear nuevas instancias de la clase bajo prueba.

De esta forma, si quisiera probar ClassA, podría pasar un objeto ClassAFactory al constructor de la clase de prueba, y si quería probar ClassB, pasaría un objeto ClassBFactory. Ambas clases están diseñadas para ser intercambiables, y dado que se supone que solo se deben probar los métodos públicos, esto parece ideal.

Pero, ¿qué tal probar el constructor? ¿Sería mejor escribir una clase de prueba abstracta e implementar pruebas de constructor en clases que hereden la clase de prueba abstracta (diferentes clases pueden crearse instancias de forma diferente)?

Si lo hiciera uso de la primera idea, supongo que tendría una clase de prueba para cada clase que se está probando, como:

class ClassATest extends [PHPUnit test case] 
{ 
    $myFactory = new ClassAFactory(); 
    $myTest = new ClassTest($myFactory); 

    $myTest->test1(); 
    $myTest->test2(); 
    //etc. 
} 

¿Cuál es la mejor manera de hacer esto? Quiero hacer una prueba general, de modo que cuando escriba nuevas clases para implementar la interfaz común, simplemente pueda poner un objeto de las mismas pruebas que las usadas para las otras. Pero, dado que las diferentes clases tendrían diferentes constructores, ¿sería mejor escribir una clase de prueba abstracta y ampliarla para cada nuevo objeto? ¿Qué piensas?

Respuesta

6

Creo que debe reconsiderar su plan. No se puede probar una interfaz y hay una buena razón para ello: las interfaces solo definen la API y no la funcionalidad, prueba la funcionalidad de la prueba. Déjame darte un ejemplo que podría ayudar. Supongamos que tiene una interfaz de "mensajería". Entonces usted implementa un EmailMessage y un SMSMessager. Ahora necesita probarlos por separado, ya que con EmailMessager necesita asegurarse de que está haciendo lo suyo, tal vez validar al destinatario (una dirección de correo electrónico) y posiblemente delegar el envío a una clase de correo electrónico, etc. Obviamente, un mensaje SMS sería diferente.

+1

En este ejemplo específico, las clases representarán destinatarios para una lista de correo. Aunque tendrán diferentes formas de hacer su trabajo, tomarán los mismos datos de un cliente y obtendrán los mismos resultados: completamente intercambiables. Me parece que si los objetos de diferentes clases que usan esa interfaz son intercambiables dentro del código del cliente, también deberían ser intercambiables dentro del código de prueba. Entonces, cuando digo que quiero probar la interfaz, lo que quiero decir es que quiero escribir una prueba en esa interfaz para probar una clase que usa esa interfaz. ¿Eso tiene sentido para ti? –

+1

No, todavía no tiene sentido. No es así como entiendo que una interfaz funcione. Es posible que desee una clase base abstracta en lugar de una interfaz para implementar el código común. No estoy seguro de qué es diferente acerca de tus clases aparte de los datos. – liquorvicar

+0

Digamos en clase, MailChimpRecipient usa la interfaz MailingListRecipient: el cliente codificado agrega a alguien a la lista configurando la dirección de correo electrónico y las propiedades del nombre del objeto del destinatario, y luego llama a un método para agregarlas. Ahora, ese método para la clase MailChimp usará la API de MailChimp para agregarlos. Digamos que en el futuro, quiero alojar mi propia lista de correo o usar otro proveedor, podría cambiar la clase con otra clase que use la interfaz MailingListRecipient. Esa clase puede hacer algo completamente diferente para agregar el destinatario, pero aún toma los mismos datos. –

6

Puede crear un caso de prueba abstracto con todos los métodos de prueba usando una propiedad que cada subclase establecerá sin requerir una fábrica. Puede probar las cualidades fijas que todas las implementaciones deben poseer.

abstract class IAdderTestCase extends PFTC 
{ 
    function testAdd() { 
     self::assertEquals(5, $this->fixture->add(2, 3)); 
    } 
    ... 
} 

class BasicAdderTest extends IAdderTestCase 
{ 
    function setUp() { 
     $this->fixture = new BasicAdder(); 
    } 
} 

PHPUnit llamará a setUp() antes de cada método de prueba. Debería llamar a todos los métodos de prueba heredados para cada subclase concreta más los adicionales, p. Ej. para probar los constructores.

+0

¡Gracias por eso! Esa parece ser la mejor manera de hacerlo, ya que puedo cambiar el método setUp para cada clase diferente. –

Cuestiones relacionadas