2012-09-27 44 views
6

Quizás me he quedado corto en mi búsqueda, pero no puedo encontrar ninguna documentación o discusión relacionada con cómo escribir una prueba unitaria para una clase/método Java que a su vez otros métodos no privados. Aparentemente, Mockito toma la posición de que tal vez haya algo mal con el diseño (no realmente OO) si se debe usar un espía para probar un método donde es necesario burlarse de las llamadas internas al método. No estoy seguro de que esto sea siempre cierto. Pero usar un espía parece ser la única forma de lograr esto. Por ejemplo, ¿por qué no podría tener un método de estilo "envoltorio" que a su vez dependa de otros métodos para la funcionalidad primitiva pero que además proporcione funcionalidad, manejo de errores, registro o diferentes ramas dependientes de los resultados de los otros métodos, etc.?Prueba unitaria para el método que llama a otros métodos múltiples usando Mockito

Así que mi pregunta es doble:

  1. sustancia es poco diseñados y código implementado para tener un método que llama internamente otros métodos?
  2. ¿Cuál es la mejor práctica y/o enfoque al escribir una prueba unitaria para dicho método (suponiendo que sea una buena idea) si uno ha elegido a Mockito como su marco burlón?

Esta podría ser una petición difícil, pero yo preferiría para aquellos que deciden a responder no sólo a volver a publicar la verborrea Mockito y/o postura sobre espías como ya soy consciente de que el enfoque y la ideología. Además, también he usado Powermockito. Para mí, el problema aquí es que Mockito desarrolló este marco donde se tuvieron que crear soluciones adicionales para apoyar esta necesidad. Entonces, supongo que la pregunta a la que quiero responder es si los espías son "malos" y Powermockito no estaba disponible, ¿cómo se supone que uno debe probar un método que llama a otros métodos no privados?

+0

Cualquier código que tenga métodos públicos llamando a otros métodos públicos (OK, tal vez excluyendo getters y setters) debe ser examinado por la posible violación del principio de SLAP y/o el antipatrón de la barcaza de basura. – Olaf

+0

¿Te importaría compartir algunas fuentes confiables con respecto a esta información? – aquacode

+0

Aquí tienes: http://www.ibm.com/developerworks/java/library/j-eaed4/index.html y http://www.drdobbs.com/four-wheel-drive-garbage-barges-and -obje/184414617. – Olaf

Respuesta

2

Si realmente necesita (o desea) evitar volver a llamar a los métodos de nivel inferior, puede anularlos en lugar de burlarse de ellos. Por ejemplo, si el método A llama a B y C, se puede hacer esto:

MyClass classUnderTest = new MyClass() { 
    @Override 
    public boolean B() {return true;} 

    @Override 
    public int C() {return 0;} 
}; 
doOtherCommonSetUp(classUnderTest); 
String result = classUnderTest.A("whatever"); 
assertEquals("whatIWant", result); 

He usado esta bastante un poco con el código heredado, donde extensa refactorización podría conducir fácilmente a la versión de software de la enfermedad de carpintero: Aísle algo difícil de probar en un método pequeño y resáltelo.

Pero si los métodos que se invocan son bastante inocuos y no requieren burla, simplemente los dejo llamar de nuevo sin preocuparme de que estoy cubriendo todos los caminos dentro de ellos.

7

¿Está mal diseñado e implementado el código para tener un método que internamente llama a otros métodos?

Realmente no. Pero yo diría que, en esta situación, el método que llama a los demás debería probarse como si los otros no se hubieran probado por separado. Es decir, lo protege de situaciones en las que sus métodos públicos dejan de llamar a los demás sin que usted se dé cuenta.

Sí, hace que (a veces) un montón de código de prueba. Creo que este es el punto: el dolor al escribir las pruebas es una buena pista de que es posible que desee considerar la extracción de esos submétodos en una clase separada.

Si puedo vivir con esas pruebas, entonces considero que los submétodos aún no se han extraído.

¿Cuál es la mejor práctica y/o enfoque al escribir una prueba unitaria para dicho método (suponiendo que sea una buena idea) si uno ha elegido Mockito como su marco burlón?

me gustaría hacer algo así:

public class Blah { 
    public int publicMethod() { 
     return innerMethod(); 
    } 

    int innerMethod() { 
     return 0; 
    } 
} 


public class BlahTest { 
    @Test 
    public void blah() throws Exception { 
     Blah spy = spy(new Blah()); 
     doReturn(1).when(spy).innerMethod(); 

     assertThat(spy.publicMethod()).isEqualTo(1); 
    } 
} 
2

Para mí, esta pregunta se relaciona fuertemente al concepto de cohesión.

Mi respuesta sería:

Es aceptable tener métodos (públicos) que llaman a otros métodos (privados) en una clase, de hecho, muy a menudo eso es lo que consideramos como un buen código. Sin embargo, hay una advertencia sobre esto en cuanto a que tu clase aún debe ser muy cohesionada. Para mí eso significa que el 'estado' de tu clase debe estar bien definido, y los métodos (comportamientos de pensamiento) de tu clase deberían estar involucrados en cambiar el estado de tus clases de maneras predecibles.

¿Es este el caso con lo que está intentando probar? Si no, puedes estar mirando una clase cuando deberías mirar dos (o más).

¿Cuáles son las variables de estado de la clase que intentas probar?

Puede encontrar que después de considerar las respuestas a este tipo de preguntas, su código es mucho más fácil de probar de la manera que cree que debería ser.

1

La verdadera pregunta debería ser:

¿Qué es lo que realmente quiero probar?

Y en realidad la respuesta debería ser:

El comportamiento de mi objeto en respuesta a las afueras cambia

Es decir, dependiendo de la forma en que uno puede interactuar con su objeto, desea probar cada escenario individual posible en una sola prueba. De esta manera, puede asegurarse de que su clase reaccione de acuerdo con sus expectativas dependiendo del escenario en el que esté proporcionando su prueba.

¿Está mal diseñado e implementado el código para tener un método que internamente llama a otros métodos?

No realmente, y realmente no! Estos llamados métodos privados que se llaman desde miembros públicos son a saber, los métodos de ayuda. ¡Es totalmente correcto tener métodos de ayuda!

Los métodos de ayuda están ahí para ayudar a romper comportamientos más complejos en pedazos más pequeños de código reutilizable dentro de la propia clase. Solo él sabe cómo debe comportarse y devuelve el estado en consecuencia a través de los miembros públicos de su clase.

No es normal ver una clase con métodos auxiliares y normalmente son necesarios para adoptar un comportamiento interno para el cual la clase no debe reaccionar desde el exterior.

Cuál es la mejor práctica y/o enfoque por escrito una prueba unitaria para un procedimiento de este tipo (asumiendo que es en sí misma una buena idea) si se ha elegido Mockito como su marco de burla?

En mi humilde opinión, no prueba esos métodos. Se hacen la prueba cuando los miembros públicos son evaluados a través del estado que espera que salga de su objeto luego de una llamada de miembro público. Por ejemplo, si usa el patrón MVP, si desea probar la autenticación de usuario, no deberá probar todos los métodos privados, ya que los métodos privados también podrían llamar a otros métodos públicos desde un objeto del que dependa el objeto bajo prueba, y así sucesivamente. En su lugar, las pruebas de su punto de vista:

@TestFixture 
public class TestView { 
    @Test 
    public void test() { 
     // arrange 
     string expected = "Invalid login or password"; 
     string login = "SomeLogin"; 
     string password = "SomePassword"; 

     // act 
     viewUnderTest.Connect(login, password); 
     string actual = viewUnderTest.getErrorMessage; 

     // assert 
     assertEqual(expected, actual); 
    } 
} 

Este método de ensayo describe el comportamiento esperado de la vista una vez que la, digamos, se hace clic en connectButton. Si la propiedad ErrorMessage no contiene el valor esperado, significa que su vista o presentador no se comportan como se esperaba. Puede verificar si el presentador se suscribió al evento Connect de su vista, o si su presentador establece el mensaje de error correcto, etc.

El hecho es que nunca necesitará probar lo que esté sucediendo en sus métodos privados, como lo hará ajuste y aplique correcciones en la depuración, lo que a su vez hace que pruebe el comportamiento de sus métodos internos simultáneamente, pero no debe escribirse ningún método de prueba especial expresamente para el método de ayuda.

Cuestiones relacionadas