Cómo implementar tests unitarios en Java

Cómo implementar tests unitarios en Java

Propósito fundamental de un test unitario

El propósito fundamental de un test unitario es verificar el comportamiento de una unidad específica de código, típicamente una clase o un método, de forma aislada. Esto significa que el test debe enfocarse exclusivamente en la lógica de la clase bajo prueba, sin depender de sistemas externos, como bases de datos, servicios web, o repositorios.

Para lograr este aislamiento, se utilizan mocks para simular el comportamiento de las dependencias externas de la clase. Mockear un objeto implica crear una versión simulada que imita las respuestas esperadas de dichas dependencias, sin ejecutar sus implementaciones reales.

Framework empleado

Las pruebas unitarias se implementan en JUnit 5, la versión más reciente del framework de pruebas unitarias para Java.

Configuración del «pom.xml»

El primer paso es comprobar que en el pom.xml del proyecto están incluidas las siguientes dependencias:

  • org.junit.jupiter:junit-jupiter-api

  • org.junit.jupiter:junit-jupiter-engine

  • org.mockito:mockito-core

  • org.mockito:mockito-junit-jupiter                                      

O, de manera equivalente, que esté incluida la dependencia «spring-boot-starter-test», que contiene los artefactos anteriores.

También es preciso comprobar que está incluido el plugin «maven-surefire-plugin», o bien que el «pom.xml» del proyecto padre contiene la dependencia «spring-boot-starter-parent».

Anotaciones principales de JUnit 5

Las principales anotaciones que se emplean en JUnit 5 son:

  • @Test: Marca un método como un caso de prueba.

  • @BeforeEach: Ejecuta el método antes de cada prueba.

  • @AfterEach: Ejecuta el método después de cada prueba.

  • @BeforeAll: Ejecuta el método una vez antes de todas las pruebas (debe ser estático).

  • @AfterAll: Ejecuta el método una vez después de todas las pruebas (debe ser estático).

  • @ExtendWith: Habilita extensiones, como MockitoExtension para integrar Mockito.

Ejemplo simplificado de test unitario

Se tiene la siguiente clase simplificada:

package com.minsait.onesait.platform.config.services.email; import org.springframework.beans.factory.annotation.Autowired; import com.minsait.onesait.platform.config.repository.EmailRepository; public class EmailServiceImpl { @Autowired EmailRepository emailRepository;     @Override     public Email findById(String id) {               var email = emailRepository.findById(id);         if (email.isPresent()) {         return email.get();         } else {         return null;         } } }

Las clases de prueba se almacenan en la carpeta «src/test/java», en el mismo paquete de la clase que testean.

Una clase de prueba la clase anterior sería:

package com.minsait.onesait.platform.config.services.email; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.when; import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import com.minsait.onesait.platform.config.model.Email; import com.minsait.onesait.platform.config.repository.EmailRepository; @ExtendWith(MockitoExtension.class) class EmailServiceImplTest {     @Mock     private EmailRepository emailRepository;     @InjectMocks     private EmailServiceImpl emailService;     private Email email;     @BeforeEach     void setUp() {         email = new Email();         email.setId("email1");     }     @Test     void testFindById_EmailExists() {         when(emailRepository.findById("email1")).thenReturn(Optional.of(email));         Email result = emailService.findById("email1");         assertEquals("email1", result.getId());     }     @Test     void testFindById_EmailNotFound() {         when(emailRepository.findById("email1")).thenReturn(Optional.empty());         Email result = emailService.findById("email1");         assertNull(result);     } }

Explicación del ejemplo:

  • @ExtendWith(MockitoExtension.class): Habilita la integración con Mockito para crear mocks.

  • @Mock: Crea un mock del repositorio EmailRepository.

  • @InjectMocks: Inyecta los mocks en la instancia de EmailService.

  • @BeforeEach: Inicializa un objeto Email antes de cada prueba.

  • @Test: Marca los métodos como casos de prueba.

  • when(...).thenReturn(...): Configura el comportamiento del mock.

  • assertEquals y assertNull: Aserciones para verificar los resultados.

Las clases de prueba se pueden construir de manera automática con herramientas de IA generativa, pero es importante verificar a posteriori que efectivamente se está probando lo que se desea probar.

Ejecución de tests unitarios

Ejecución en Eclipse

Para ejecutar los test unitarios en Eclipse, se abre la clase que contiene los test, se hace clic con el botón derecho del ratón, y se ejecuta: «Run As -> JUnit Test».

image-20250627-082900.png

Para comprobar el resultado de la ejecución, se pulsa en «Window -> Show View -> Other…», y se selecciona la vista «Java -> JUnit».

Ejecución con Maven

Para ejecutar los test unitarios con Maven es preciso situarse en la raíz del proyecto (o del módulo que se desee probar) y, desde la consola, ejecutar el comando:

mvn test