Los test unitarios son un procedimiento para comprobar que en determinadas funciones obtenemos los resultados esperados, sin necesidad de arrancar la aplicación e ir a la funcionalidad a través de la interfaz.
Una ventaja de realizar las pruebas unitarias, es que podemos asegurarnos de no “romper nada” con los nuevos desarrollos siempre que se ejecuten dichos test satisfactoriamente.
En Java y Spring, dos herramientas populares para realizar pruebas unitarias efectivas son JUnit y Mockito.
JUnit
JUnit es un framework que nos permite escribir y ejecutar test de forma fácil.
Para añadirlo en nuestro proyecto, usamos la siguiente dependencia:
// Testing
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation('org.springframework.security:spring-security-test')
Manos a la obra: ejemplo básico de tests unitarios
Si tenemos una clase llamada Calculadora con esta función:
public int sumar(int[] numeros){
OptionalInt number = Arrays.stream(numeros).reduce(Integer::sum);
return number.orElse(0);
}
Podemos crear un test para comprobar que la suma es correcta, por ejemplo, estos dos casos:
2 + 1 = 3
2 + 1 + 4 = 7
@SpringBootTest
public class CalculadoraTest {
Calculadora calculadora = new Calculadora();
@Test
void whenCalculateSum_given2and1_then3() {
int resultado = calculadora.sumar(new int[]{2, 1});
int expectedResultado= 3;
Assertions.assertEquals(expectedResultado,resultado);
}
@Test
void whenCalculateSum_given2and1and4_then7() {
int resultado = calculadora.sumar(new int[]{2, 1, 4});
int expectedResultado= 7;
Assertions.assertEquals(expectedResultado,resultado);
}
}
Como se puede observar, es recomendable usar una buena nomenclatura para los nombres de las funciones para saber a qué prueba corresponde.
Si ejecutamos el test nos aparecerá que ha sido satisfactorio:
Siguiente paso: crear tests que usen otros servicios
Es común tener aplicaciones que se conectan a bases de datos o incluso que hagan peticiones contra endpoints para obtener datos.
Como norma general, debemos evitar que los test se comuniquen a estos servicios externos, dado que podemos crear datos que no son reales.
Para evitar esto, podemos mockear los servicios que usen estos recursos.
¿Qué es mockear?
Simular los métodos de un objeto, es decir, no llega a ejecutar el código de ese método. Por defecto, retorna valores por defecto de la clase que retorne dichos métodos.
Adicionalmente, podemos indicar cierto comportamiento al realizarse un método, recordamos que, siempre sin ejecutar el código real de esa clase
Ejemplo:
Data esta clase de servicio, que tiene como dependencia un repositorio de base de datos:
@Service
public class PersonaServiceImplement implements PersonaService{
@Autowired
private PersonaRepository repository;
@Override
public Persona getPersonaById(int id) {
return repository.findById(id).orElse(null);
}
@Override
public List<Persona> getListPersonas() {
return repository.findAll();
}
}
Necesitamos comprobar que los métodos devuelven los resultados esperados, es decir, por ejemplo del método getListPersonas , comprobar que recibirá los mismos elementos que obtiene de PersonaRepository.
Para esto creamos la siguiente clase de test:
package com.rbr.unittesting.services;
import com.rbr.unittesting.data.PersonaRepository;
import com.rbr.unittesting.domain.Persona;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
@SpringBootTest
public class PersonaServiceTest {
@InjectMocks
private PersonaService personaService= new PersonaServiceImplement();
@Mock
private PersonaRepository repository;
@Test
void whenGetAllPersonas_givenListThreeElement_thenEqualsNumberElements() {
when(repository.findAll()).thenReturn(this.getListTresPersonas());
List<Persona> personas = personaService.getListPersonas();
int numeroPersonas = personas.size();
int expectedNumeroPersonas = 3;
Assertions.assertEquals(numeroPersonas,expectedNumeroPersonas);
}
private List<Persona> getListTresPersonas(){
return Arrays.asList(new Persona(1,"Carlos","Pérez"),
new Persona(2,"Maria","Cuellar"),
new Persona(3,"Esther","García"));
}
}
Con la anotación @Mock hemos mockeado la clase PersonaRepository para que no acceda a la base de datos y devuelva lo que deseemos en el método findAll
Dentro del método de test, le hemos indicado que cuando se llame al método findAll , obtengamos la lista de la función getListTresPersonas.
Ahora, comprobamos que obtenemos 3 personas para dar el test como correcto.
Como podemos observar, aún faltarían muchas pruebas a realizar, como por ejemplo, comprobar que el nombre sea igual de cada elemento, pero con esto tenemos una base para hacer los test más básicos.
Foto de Mohammad Rahmani en Unsplash