Cuando una clase tenga demasiados tests, nos podemos encontrar en la situación de que estos tests siempre tengan el mismo preámbulo y por lo tanto haya código duplicado en ellos. Por ejemplo, si estamos probando una clase con 10 métodos, y hacemos 10 tests para probar cada uno de esos métodos, tal vez cada uno de ellos tenga en la parte superior de su código la misma instanciación de la misma clase.
@Test
public void testName() {
Customer cus = new Customer("Juan", "Palomo");
assertEquals("Juan", cus.getName());
}
@Test
public void testSurname() {
Customer cus = new Customer("Juan", "Palomo");
assertEquals("Palomo", cus.getSurname());
}
En este caso, tener duplicada la rutina de inicialización es un problema porque si cambia la forma en la que se instancian objetos de esta clase, tendremos que repetir el mismo cambio 10 veces. Similarmente, si después de trabajar con este objeto hay que limpiar otras instancias de clases colaboradoras que han participado en un test, habrá que tener ese código duplicado.
Con Before y After podemos evitar esto. Se tratan de dos anotaciones que pondremos a métodos de una clase de test. Cuando un método está etiquetado con la anotación @Before, lo que JUnit hace es ejecutar ese método antes de cualquier otro método anotado como test en la misma clase. Similarmente, si anotamos un método con la anotación @After, JUnit ejecutará ese método después de correr los métodos declarados como test en una clase.
Si vas a usar Before y After, tienes que tener en cuenta que las variables locales de los métodos no se comparten. Por lo tanto, lo normal en estos casos será utilizar atributos de instancia dentro de la clase del tests. Puedes imaginarlo como un constructor especializado para usar en tus tests.
public class CustomerTest {
private Customer cus;
@Before
public void before() {
cus = new Customer("Juan", "Palomo");
}
@Test
public void testName() {
assertEquals("Juan", cus.getName());
}
@Test
public void testSurname() {
assertEquals("Palomo", cus.getSurname());
}
}
Un ejemplo más completo que nos permitiría imprimir por la salida estandar del runner el ciclo de ejecución de un test:
public class LifecycleTest {
@Test
public void testPrueba1() {
System.out.println("test - Prueba 1");
}
@Test
public void testPrueba2() {
System.out.println("test - Prueba 2");
}
@Before
public void before() {
System.out.println("before");
}
@After
public void after() {
System.out.println("after");
}
}
En este caso, veremos por pantalla lo siguiente:
before
test - Prueba 1
after
before
test - Prueba 2
after
Podemos imaginar las tres primeras líneas como el ciclo before-test-after de uno de los tests, y las otras tres como el ciclo before-test-after del otro test. Aquí, de hecho, vemos una consecuencia muy importante: Before y After se van a ejecutar tantas veces como tests haya en una clase, y siempre van a tratar al test como si fuese el queso de un sandwich, es decir, siempre va a quedar por fuera el Before y el After, envolviendo al Test.