Pruebas de integración de aplicaciones Java con Docker
El desarrollo moderno de Java es impensable sin pruebas de calidad. Sin embargo, las pruebas unitarias a menudo no logran identificar problemas que surgen cuando los componentes interactúan con bases de datos reales, colas de mensajes o APIs externas. Aquí es donde las pruebas de integración vienen al rescate, y Docker hace que este proceso sea simple, reproducible y aislado. En este artículo, analizaremos cómo usar Docker de manera efectiva para las pruebas de integración de aplicaciones Java, utilizando la biblioteca Testcontainers y Docker Compose.
¿Por qué Docker cambia las reglas del juego en las pruebas de integración?
El enfoque tradicional de las pruebas de integración a menudo requiere instalar y configurar todas las dependencias (bases de datos, brokers de mensajes) en la máquina local del desarrollador o en el servidor CI. Esto conlleva una serie de problemas:
- Inestabilidad del entorno: Diferentes versiones de SGBD, conflictos de puertos, diferencias entre el entorno de desarrollo y producción.
- Complejidad en la configuración de CI/CD: Necesidad de instalar y configurar manualmente los servicios en el pipeline.
- Contaminación de datos: Los datos de prueba pueden permanecer en la base de datos local, afectando ejecuciones posteriores.
- Paralelización: La ejecución simultánea de pruebas en una misma máquina puede provocar conflictos.
Docker resuelve estos problemas proporcionando contenedores ligeros, aislados y efímeros. Cada prueba (o conjunto de pruebas) puede iniciar su propia instancia de PostgreSQL, Redis o Kafka, y una vez finalizada la prueba, destruirla. Esto garantiza la limpieza y repetibilidad de los resultados.
Configuración del proyecto: Testcontainers vs Docker Compose
Existen dos enfoques principales para integrar Docker en las pruebas de Java. Analicemos ambos.
1. Testcontainers: biblioteca para gestionar contenedores desde el código
Testcontainers es una biblioteca de Java que permite gestionar el ciclo de vida de los contenedores Docker directamente desde tus pruebas. Es el estándar de facto para las pruebas de integración en el ecosistema de Spring Boot y más allá.
Ventajas:
- Gestión programática: los contenedores se inician y detienen automáticamente.
- Soporte para servicios populares "listos para usar" (GenericContainer, PostgreSQLContainer, KafkaContainer, etc.).
- Selección automática de puertos libres (evitamos conflictos).
- Ideal para pruebas de integración modulares.
Ejemplo: Prueba de un controlador REST con PostgreSQL
Añade la dependencia a tu pom.xml (Maven):
<dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers</artifactId> <version>1.19.3</version> <scope>test</scope></dependency><dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <version>1.19.3</version> <scope>test</scope></dependency>Ahora escribamos una prueba para una aplicación Spring Boot que funciona con PostgreSQL:
import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.boot.test.web.client.TestRestTemplate;import org.springframework.http.ResponseEntity;import org.testcontainers.containers.PostgreSQLContainer;import org.testcontainers.junit.jupiter.Container;import org.testcontainers.junit.jupiter.Testcontainers;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnviron