Quiero poder dividir una prueba grande en pruebas más pequeñas para que cuando pasen las pruebas más pequeñas implican que la prueba grande también pasará (por lo que no hay razón para ejecutar la prueba) gran prueba original). Quiero hacer esto porque las pruebas más pequeñas generalmente toman menos tiempo, menos esfuerzo y son menos frágiles. Me gustaría saber si hay patrones de diseño de prueba o herramientas de verificación que puedan ayudarme a lograr esta división de prueba de manera robusta.Dividir una prueba en un conjunto de pruebas más pequeñas
Me temo que la conexión entre las pruebas más pequeñas y la prueba original se pierde cuando alguien cambia algo en el conjunto de pruebas más pequeñas. Otro temor es que el conjunto de pruebas más pequeñas no cubra realmente la gran prueba.
Un ejemplo de lo que estoy apuntando en:
//Class under test
class A {
public void setB(B b){ this.b = b; }
public Output process(Input i){
return b.process(doMyProcessing(i));
}
private InputFromA doMyProcessing(Input i){ .. }
..
}
//Another class under test
class B {
public Output process(InputFromA i){ .. }
..
}
//The Big Test
@Test
public void theBigTest(){
A systemUnderTest = createSystemUnderTest(); // <-- expect that this is expensive
Input i = createInput();
Output o = systemUnderTest.process(i); // <-- .. or expect that this is expensive
assertEquals(o, expectedOutput());
}
//The splitted tests
@PartlyDefines("theBigTest") // <-- so something like this should come from the tool..
@Test
public void smallerTest1(){
// this method is a bit too long but its just an example..
Input i = createInput();
InputFromA x = expectedInputFromA(); // this should be the same in both tests and it should be ensured somehow
Output expected = expectedOutput(); // this should be the same in both tests and it should be ensured somehow
B b = mock(B.class);
when(b.process(x)).thenReturn(expected);
A classUnderTest = createInstanceOfClassA();
classUnderTest.setB(b);
Output o = classUnderTest.process(i);
assertEquals(o, expected);
verify(b).process(x);
verifyNoMoreInteractions(b);
}
@PartlyDefines("theBigTest") // <-- so something like this should come from the tool..
@Test
public void smallerTest2(){
InputFromA x = expectedInputFromA(); // this should be the same in both tests and it should be ensured somehow
Output expected = expectedOutput(); // this should be the same in both tests and it should be ensured somehow
B classUnderTest = createInstanceOfClassB();
Output o = classUnderTest.process(x);
assertEquals(o, expected);
}
+1 Mantener las pruebas en una misma clase (y nombrar la clase de prueba como lo hizo) hará que sea menos probable que alguien pueda frenar accidentalmente la conexión entre la prueba original y las pruebas más pequeñas. Gracias por esto. Todavía me falta una forma automática de saber que las pruebas más pequeñas implican que la gran prueba pasaría. – mkorpela
@mkorpela, ¿puede explicar un poco sobre por qué es importante que las pruebas más pequeñas impliquen que la gran prueba pasaría? Si falla una de las pruebas más pequeñas, ¿no es eso suficiente para indicar que existe un problema? En cualquier caso, la mayoría de los corredores de prueba tienen una indicación del estado de toda la clase de prueba. Por ejemplo, los corredores de prueba NUnit y Eclipse JUnit marcan la clase de prueba como "verde" si todas las pruebas en la clase pasan, y "roja" si fallan otras pruebas. "TheBigTest" se marcará como pasar si pasan todas las pruebas más pequeñas. –
@Hurme, no puedo eliminar la prueba original si puede fallar en una situación en la que pasarían las pruebas más pequeñas. – mkorpela