Testing en java: Uso de JUnit y Mockito
El testing es un conjunto de posibles pruebas que se realizan sobre los componentes del sistema de manera individual, por ejemplo, testear el funcionamiento de una clase o de una función de la propia clase.
La ejecución de las pruebas sigue el esquema de la «caja negra», es decir, introduciendo entradas en una caja cuyo interior desconocemos y recibiendo unas salidas (deterministas). El testeo es una aplicación de asbtracción.
La unidad atómica del testing es la prueba unitaria, se realiza sobre unidades de trabajo, entendiendo como tal a la operación o conjunto de operaciones que generan un cambio en el sistema.
Un test unitario consta de tres secciones:
- La etapa de preparación (Arrange), donde se introducen los valores de entrada.
- Ejecución (Act): Se ejecuta la prueba sobre la unidad de trabajo.
- Etapa de comprobación (Assert): Se comprueban las condiciones esperadas.
Las pruebas unitarias son independientes, actúan como unidad funcional completa.
Los datos se traducen a través de la técnica Mocking, una manera de engañar a la prueba para que trabaje con datos introducidos a mano (conocidos como hardcodeados), haciendo el testeo pase a ser independiente de los datos recogidos en una base de datos, ficheros etc.
Las pruebas unitarias pueden ser manuales si las desarrolla el programador a través de la interacción humana o automatizadas si son producto del software.
Pasando al aspecto práctico, en springboot disponemos de la anotación @test para definir un componente como test, haciendo uso de los assert anteriormente mencionados, podemos especificar las condiciones que debe cumplir la salida de nuestro test:
@Test
public void sumar(){
double resultado = 5; // 3+2
ClaseATestear instancia = new ClaseAtestear();
Assert.assertEquals(5, instancia.sumar(3,2),0) // Assert: (resultadoEsperado, operación, variaciónAceptada(llamada tambien delta))
}
Una buena práctica es la definición de un espacio de testeo donde se definan las entradas que serán llamadas recurrentemente, con el fin de simplificar el código:
*Con JUnit 5 (jupiter), las anotaciones @After y @Before quedan en desuso en detrimento de de @BeforeAll y @AfterAll, estas anotaciones requieren que el método sea estático.
Sigue siendo válido el uso de @BeforeEach y @AfterEach.
ClaseAtestear instancia;
@BeforeAll
public static void init(){
instancia = new ClaseATestear();
}
@Test...
Del mismo modo disponemos de la anotación que permite ejecutar un método tras cada prueba unitaria.
@AfterAll
public void close(){
System.out.println("Testeo realizado.");
}
Existen tambien las anotación @BeforeClass y @AfterClass, la cual funciona de un modo similar a before, con la excepción de que se ejecuta una única vez.
Una vez hayamos definido las estructuras de testeo que consideremos, podremos ver el porcentaje de nuestro proyecto que está abarcado por el testeo mediante el test con cobertura (Coverage Run).
Es importante mencionar que lo más adecuado es marcar la carpeta «test» como «Test source Root» en configuración.
Uso de Mockito:
Cuando integramos servicios en nuestro proyecto, a menudo necesitamos recurrir a fuentes de datos que en producción no disponen de datos suficientes o cuyo acceso es más costoso que la ejecución sobre unos datos hardcodeados, en estos contextos podemos recurrir a los Mocks.