Glosario · CI/CD y DevOps
Testcontainers
También llamado: Testcontainers for Java, testcontainers-node, test containers
Definición
Librería que arranca dependencias reales, como bases de datos, brokers o navegadores, en contenedores Docker desechables desde tu código de test y luego los elimina.
Testcontainers es una librería de código abierto, disponible para Java, Node.js, .NET, Go, Python y otros lenguajes, que controla Docker desde dentro de tus tests. Un test pide “una base de datos Postgres 16”, la librería arranca un contenedor, espera a que esté listo, te da los datos de conexión y elimina el contenedor cuando el test termina. Pruebas contra el motor de base de datos real en lugar de contra un sustituto en memoria o un entorno compartido.
Ejemplo (Testcontainers para Java 1.x, JUnit 5)
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Testcontainers
class DatabaseIT {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");
@Test
void canQueryTheDatabase() throws Exception {
try (Connection conn = DriverManager.getConnection(
postgres.getJdbcUrl(), postgres.getUsername(), postgres.getPassword());
ResultSet rs = conn.createStatement().executeQuery("SELECT 1")) {
assertTrue(rs.next());
}
}
}
Un campo static comparte un único contenedor entre todos los tests de la clase; un campo de instancia arrancaría uno nuevo por test. En una suite real apuntarías tu repositorio o tu contexto de Spring a getJdbcUrl() y ejecutarías antes las migraciones.
Por qué importa
Los tests de integración contra H2 o SQLite a menudo pasan mientras la base de datos de producción rechaza el mismo SQL, porque difieren los dialectos, las restricciones y el comportamiento de las transacciones. Testcontainers te da el motor real casi con la comodidad de un mock, y cada ejecución parte de un estado limpio, lo que elimina la inestabilidad (flakiness) por datos compartidos.
Lo que conviene saber
- Necesita un runtime compatible con Docker en la máquina y en los runners de CI. Los runners Ubuntu alojados por GitHub tienen Docker disponible.
- Arrancar un contenedor cuesta segundos. Comparte contenedores por clase o por suite y reinicia los datos entre tests en lugar de reiniciar el contenedor.
- Fija las versiones de las imágenes para que coincidan con producción.
- Existen módulos listos para servicios comunes (Postgres, MySQL, Kafka, LocalStack, Selenium y más), y
GenericContainercubre cualquier otra imagen. - Complementa a los test doubles en lugar de sustituirlos: los tests unitarios deben seguir ejecutándose en memoria y siendo rápidos.