Glossario · CI/CD e DevOps
Testcontainers
Detto anche: Testcontainers for Java, testcontainers-node, Testcontainers Java, test con container Docker
Definizione
Libreria che avvia dipendenze reali come database, broker o browser in container Docker usa e getta direttamente dal codice dei test, per poi rimuoverli.
Testcontainers è una libreria open source, disponibile per Java, Node.js, .NET, Go, Python e altri linguaggi, che controlla Docker dall’interno dei tuoi test. Un test chiede “un database Postgres 16”, la libreria avvia un container, aspetta che sia pronto, ti fornisce i dati di connessione e rimuove il container al termine del test. Testi contro il vero motore di database invece che contro un sostituto in memoria o un ambiente condiviso.
Esempio (Testcontainers for 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 condivide un solo container tra tutti i test della classe; un campo di istanza ne avvierebbe uno nuovo per ogni test. In una suite reale punteresti il tuo repository o il contesto Spring a getJdbcUrl() ed eseguiresti prima le migrazioni.
Perché è importante
I test di integrazione su H2 o SQLite spesso passano mentre il database di produzione rifiuta lo stesso SQL, perché dialetti, vincoli e comportamento delle transazioni sono diversi. Testcontainers ti dà il motore reale con quasi la stessa comodità di un mock, e ogni esecuzione parte da uno stato pulito, eliminando la flakiness dovuta ai dati condivisi.
Cose da sapere
- Richiede un runtime compatibile con Docker sulla macchina e sui runner di CI. I runner Ubuntu ospitati da GitHub hanno Docker disponibile.
- L’avvio dei container costa qualche secondo. Condividi i container per classe o per suite e reimposta i dati tra un test e l’altro invece di riavviare il container.
- Fissa le versioni delle immagini in modo che corrispondano alla produzione.
- Esistono moduli già pronti per i servizi più comuni (Postgres, MySQL, Kafka, LocalStack, Selenium e altri), e
GenericContainercopre qualsiasi altra immagine. - Integra i test double invece di sostituirli: gli unit test dovrebbero comunque restare in memoria e veloci.