2011-07-28 12 views
5

tengo un adaptador del I1 a ILogger implementado como esto:Cómo escribir JUnit para Adapter sin código demasiado complicado?

class BAdapter() implements I1 
{ 
    void logA() { // nothing } 
    void logB() { new BLogger().log() } 
    void logC() { // nothing } 
} 

me gustaría escribir prueba unitaria, para verificar el funcionamiento, pero me pareció un poco problemático, ya que no puedo inyectar mi objeto de burla en su lugar de BLogger, o verifique el valor de retorno. Encontré varias soluciones posibles, pero no estoy seguro, cuál es la mejor.

Caso uno: Añadir void setLogger(Logger l) a la clase BAdapter.

class BAdapter() implements I1 
{ 
    private Logger logger = new BLogger(); 

    public void logB() { logger.log() } 
    public void setLogger(Logger l) { logger = l } 
    .. //rest of methods 
} 

Contras: ¿Por qué añadir colocador que nunca se utiliza en "real", el código no pruebas?

Caso dos: Agregar método de fábrica protegido y sublcass BAdapter en el paquete de prueba.

class BAdapter() implements I1 
{ 
    public void logB() { createLogger().log() } 
    protected Logger createLogger() { retrun new BLogger() } 
    .. //rest of methods 
} 

class BAdapterForTesting extends BAdapter() 
{ 
    protected Logger createLogger() { retrun new MockBLogger() } 
} 

Contras: No estoy seguro, si esta es una solución limpia y elegante, pero no veo muchas desventajas aquí.

Caso tres: Utilice el patrón Abstract Factory.

class BAdapter() implements I1 
{ 
    public void logB() { AbstractFactory.getFactory().getBLogger().log() } 
    .. //rest of methods 
} 

Y en algún lugar en las pruebas:

AbstractFactory.setFactory(new MockLoggersFactory()) 

Contras: Esto es demasiado complejo, ¿no es así?

la caja cuatro: Retorno de Boole, por ejemplo, cuando se llevó a cabo el registro. P.ej.

class BAdapter() implements I1 
{ 
    Boolean logA() { return false; } 
    Boolean logB() { return new BLogger().log() } 
    Boolean logC() { return false; } 
} 

Contras: Esto es una especie de wourkaround. ¿Por qué devolver algún valor, cuando nadie lo necesita en un código "real" sin pruebas?

¿Mejor solución? ¿Hay algo mejor?

Respuesta

2

De su código es difícil decir exactamente qué clase de prueba está tratando de lograr, pero Me gustaría ir con el Caso Uno con la advertencia de que usaría la inyección en el código 'real' también.

Uno de los beneficios de la inyección es que hace que la clase, en este caso su adaptador, sea más reutilizable. Forzar el método logB para siempre delegar a una instancia de BLogger establece ese comportamiento en piedra en tiempo de compilación. Si quiero que el adaptador se delegue en otro tipo de Logger no puedo usarlo y, por lo tanto, es un poco menos reutilizable.

+0

Encontré un enfoque similar en JUnit in Action book. El código de prueba es el cliente de su código como cualquier otro, por lo que es bueno volver a factorizar o actualizar el código para adaptarse a los requisitos de prueba de la unidad. –

0

IMVHO crea código especialmente para ser utilizado por las pruebas y en ninguna otra parte no es una buena idea, ya que puede exponer la funcionalidad que no se debe usar, sin embargo, algunos pueden pensar que usarlo es genial y sorprenderse.

Esto nos deja con el caso 3, que es un enfoque generalmente muy bueno, pero si solo se va a utilizar durante las pruebas, es un poco exagerado.

me gustaría sugerir el uso de algún marco de burla adicional como PowerMock que puede cambiar los campos privados en las clases de forma conveniente:

class BAdapter() implements I1 
{ 
    private Logger logger = new BLogger(); 

    public void logB() { logger.log() } 
    .. //rest of methods 
} 

y luego durante las pruebas de intercambio el campo para algunos simulacro:

Whitebox.setInternalState(loggerInstance, "logger", new MockLogger()); 

más información: http://code.google.com/p/powermock/wiki/BypassEncapsulation

Los marcos de burla son un gran activo durante las pruebas, por lo que saberlos ayuda s mucho

Cuestiones relacionadas