2009-08-18 8 views
19

Estoy tratando de implementar pruebas unitarias para un proyecto, utiliza un proyecto heredado de "utilidad" que está plagado de métodos estáticos y muchas de las clases son definitivas o sus métodos son definitivos. No puedo actualizar el proyecto heredado en absoluto.¿Cómo puedo probar los métodos finales y estáticos de un proyecto de utilidad?

JMock y EasyMock se atragantan con los métodos finales, y no veo una buena manera de probar las llamadas estáticas. ¿Qué técnicas hay para probar esto?

+0

¿Hay alguna razón por la que necesite utilizar un framework de Mock? –

+0

Sí, las llamadas al método usan propiedades JNDI para conectarse a la base de datos y a JMS, no quiero implementar todas las piezas para mi prueba. –

+0

¿Puede refactorizar algún código heredado para ayudarlo? –

Respuesta

21

Si usted es capaz de refactorizar su código, se puede envolver sus llamadas a los métodos finales/estáticos en los métodos de instancia simples, por ejemplo:

protected Foo doBar(String name) { 
    return Utility.doBar(name); 
} 

Esto le permite anular el método de envoltura en el prueba unitaria para devolver una instancia falsa de Foo.

Alternativamente, puede utilizar Powermock, que se extiende EasyMock (y Mockito) para permitir burlarse de métodos finales y estáticas:

PowerMock es un marco que se extienden otras bibliotecas simuladas tal como EasyMock con capacidades más potentes. PowerMock utiliza un cargador de clases personalizado y manipulación de códigos de bytes para permitir la burla de métodos estáticos, constructores, clases y métodos finales, métodos privados, eliminación de inicializadores estáticos y más.

Aquí es una prueba example burlarse de un método static final, el ejemplo muestra cómo burlarse de algunos otros tipos también:

@Test 
public void testMockStaticFinal() throws Exception { 
    mockStatic(StaticService.class); 
    String expected = "Hello altered World"; 
    expect(StaticService.sayFinal("hello")).andReturn("Hello altered World"); 
    replay(StaticService.class); 

    String actual = StaticService.sayFinal("hello"); 

    verify(StaticService.class); 
    assertEquals("Expected and actual did not match", expected, actual); 

    // Singleton still be mocked by now. 
    try { 
     StaticService.sayFinal("world"); 
      fail("Should throw AssertionError!"); 
    } catch (AssertionError e) { 
     assertEquals("\n Unexpected method call sayFinal(\"world\"):", 
      e.getMessage()); 
    } 
} 
+0

+1 para PowerMock ya que la refactorización está descartada. –

+0

esto parece lo que necesito, ¿sabes si funciona en una compilación Maven? –

+0

No lo he intentado aún, pero parece que sí: http://code.google.com/p/powermock/wiki/EasyMock_maven –

5

¿Qué tal un nivel de indirección/inyección de dependencia?

Dado que el proyecto de utilidad heredado es su dependencia, cree una interfaz para separarlo de su código. Ahora su implementación real/producción de esta interfaz delega a los métodos de utilidad heredados.

public LegacyActions : ILegacyActions 
{ 
    public void SomeMethod() { // delegates to final/static legacy utility method } 
} 

Para las pruebas, puede crear una maqueta de esta interfaz y evitar la interacción con el thingie utilidad legado.

1

Si su método no refactorizable utiliza algo así como JNDI para conectarse a otro servicio, consideraría comenzar un servicio JDNI y poblarlo con los resguardos que usted controla. Es un dolor pero relativamente sencillo. Puede significar configurar una base de datos o un escucha JMS o lo que sea, pero debe haber una implementación java liviana que pueda incluir en las pruebas.

+0

Eso está bien para las pruebas de integración, pero las pruebas unitarias no deberían necesitar una base de datos –

+0

Puede burlarse de la base de datos e inyectar ese simulacro en el JNDI. – extraneon

+1

@Rich Vendedor: Estoy de acuerdo, pero si tuviera algunos huevos, podría tener tocino y huevos, si tuviera un poco de tocino. Con eso me refiero a que la pregunta original decía que no podía refactorizar el código y quería agregar pruebas. A veces tienes que trabajar con lo que tienes, no con lo que quieres. –

3

JMockit le permite simular métodos estáticos y clases finales. Supongo que usa algunos classloadin-fu, aunque realmente no lo he investigado.

expectativas JMockit API permite expectativas que se establezcan en cualquier tipo de invocación de método (en las interfaces, clases abstractas, final hormigón o clases no finales, y en métodos estáticos), así como en la clase instanciación a través de cualquier constructores.

1

Como ya se indicó, se puede usar JMockit. Un ejemplo:

@Test 
public void mockStaticAndFinalMethods(final LegacyService mock) 
{ 
    new NonStrictExpectations() 
    { 
     { 
     LegacyService.staticMethod("hello"); result = "Hello altered World"; 
     } 
    }; 

    String actual = LegacyService.staticMethod("hello"); 
    new LegacyService().finalMethod(123, "test"); 

    assertEquals("Hello altered World", actual); 

    new Verifications() 
    { 
     { 
     mock.finalMethod(123, "test"); // verify this call occurred at least once 
     } 
    }; 
} 

La página principal del proyecto JMockit contiene una comparación con PowerMock, para los interesados.

-1

JMock junto con JDave pueden simular los métodos y clases finales, si es necesario. Here son instrucciones. Dicho esto, trataría este código heredado (como ya han sugerido otros) como una dependencia externa e interfaces de construcción y las simularé. Es otra capa de indirección, pero como no puedes cambiar ese código heredado, parece ser razonable.

Cuestiones relacionadas