2011-01-26 13 views
9

Estoy usando EasyMock para simular objetos en mis pruebas. Pero, ¿cómo me burlo de los objetos que se crean en otro lugar en mi código? Mira el siguiente código psudo. Quiero burlar WebService # getPersonById, ¿cómo hago eso?¿Cómo me burlo de los objetos que no puedo instanciar en mis pruebas?

public class Person { 
    public Person find(int id) { 
    WebService ws = new WebService(); 
    return ws.getPersonById(id); 
    } 
} 

public class PersonTest { 
    testFind() { 
    // How do I mock WebService#getPersonById here? 
    } 
} 

Respuesta

0

Terminé usando JMockit en su lugar. Tiene soporte para burlarse de todas las instancias de una clase.

+2

Lamento decirlo, pero es una pena. En mi humilde opinión, una de las mejores cosas del desarrollo basado en pruebas es que se ve obligado a pensar y replantear su diseño. Encontrar algo que no sea fácilmente comprobable frente a las interfaces es una buena señal de olor a código. @hvgotcodes ha trazado un buen camino, cómo puede hacer que su código sea más fácil de mantener, flexible y comprobable. No me gustaría tirar eso por una simple solución. –

9

La burla normalmente funciona bien si usa la inversión de control y la inyección de dependencia para conectar sus servicios. Por lo que su persona debe ser similar

public class Person() { 
    WebService ws = null; 

    // or use setters instead of constructor injection 
    Persion(WebService ws) { 
    this.ws = ws; 
    } 
    public Person find(int id) { 
    return ws.getPersonById(id); 
    } 
} 

de esperar, está claro que con este cambio, ahora se puede crear un control simulado y se burlan de servicio Web y sólo tienes que conectarlo en su prueba, ya que cuando se crea la persona para poner a prueba , puedes pasar el simulacro al constructor (o al instalador si vas por esa ruta).

en su entorno real, el contenedor IoC inyectará el servicio web real en.

Ahora, si usted no quiere tratar con todas estas cosas COI, lo que hay que hacer es desacoplar el servicio web de su Persona (que debería llamarse PersonService o algo, no solo Person, que denota entidad). En otras palabras, la forma en que se escribe el código solo puede usar un tipo de servicio web. Es necesario para que sea lo que la persona sólo necesita un poco de tipo de servicio Web, no el específico que haya codificado de entrada.

Por último, en el código como está escrito, WebService es una clase, no una interfaz. El WebService debe ser una interfaz, y debe poner en algún tipo de implementación. EasyMock funciona bien con interfaces; podría simular clases concretas (hace tiempo que no lo usé), pero como principio de diseño debe especificar la interfaz requerida, no la clase concreta.

+0

+1 - esto es casi exactamente lo que agregué en mi respuesta (ahora eliminada). –

+0

+1 Buena respuesta. Manera de ser un maestro – jwir3

+1

Supongo que se podría decir que hay un olor a código cuando no se puede burlar de un objeto, entonces? :-) Creo que tengo que volver a pensar en mi implementación. Muchas gracias por tu increíble respuesta y ejemplo. – Sven

0

En primer lugar necesita hacer una simulación de ws, usualmente inyectándola.

public abstract class Person() { 
    public Person find(int id) { 
    WebService ws = createWebService(); 
    return ws.getPersonById(id); 
    } 
    protected abstract WebService createWebService(); 
} 

A continuación, puede deslizarse hacia adentro y utilizar EasyMock.expect para configurar el retorno

public class PersonTest() { 
    testFind() { 
    WebService mock = EasyMock.createMock(WebService.class); 
    Person p = new Persion() { 
     protected WebService createWebService() { 
     return mock; 
     } 
    } 
    EasyMock.expect(mock.getPersonById()).andReturn(dummyValue); 
    //Test code 
    } 
} 

Usted también necesitará un PersonImpl tener el verdadero método de crear.

1

Creo que te estás perdiendo un problema mucho más grande. La dificultad de las pruebas es intentar decirte algo, que tener un objeto Person (parte del dominio) que también utiliza un servicio remoto para encontrar más instancias de sí mismo (parte del sistema) es una mezcla de preocupaciones. Separe la obtención de Person s del objeto Person y obtendrá un código más limpio y portátil.

No confunda la comodidad inmediata (tengo un objeto Person en mi mano, así que lo usaré para obtener más) con facilidad de mantenimiento.

3

No hay forma de hacerlo con EasyMock (o la mayoría de las demás API de burla). Con JMockit, por el contrario, una prueba de este tipo sería muy simple y elegante:

public class PersonTest 
{ 
    @Test 
    public testFind(@Mocked final WebService ws) { 
     final int id = 123; 

     new NonStrictExpectations() {{ 
      ws.getPersonById(id); result = new Person(id); 
     }}; 

     Person personFound = new Person().find(id); 

     assertEquals(id, personFound.getId()); 
    } 
} 

Por lo tanto, cada vez que nos encontramos con una situación en la que una unidad de prueba no se puede escribir en un primer momento, no podemos concluir automáticamente que el código bajo prueba no puede ser revisado y necesita ser refactorizado.A veces será el caso, pero ciertamente no siempre. Tal vez el problema no esté en el código bajo prueba, sino en las limitaciones de una herramienta burlona en particular que se está utilizando.

Cuestiones relacionadas