Java Testcontainers (2.x)
Exécutez des dépendances réelles (bases de données, brokers, caches) dans Docker pour les tests d'intégration. Cette skill est indépendante du framework. Si le projet utilise Spring Boot et que la skill spring-boot-testing est installée, utilisez-la pour @ServiceConnection, @DynamicPropertySource et les tranches de test ; pour Quarkus, appuyez-vous sur Dev Services (skills/docs Quarkus), et non sur des conteneurs câblés manuellement.
Workflow
- Détectez la version existante (
pom.xml/build.gradle) et le framework de test (JUnit Jupiter). Testcontainers 2.x n'a pas de support JUnit 4. - Choisissez le plus petit conteneur qui correspond à la production (même moteur de BD et version majeure ; jamais H2 comme substitut pour un comportement qui vous importe).
- Sélectionnez un cycle de vie (tableau ci-dessous), configurez l'attente, câblez les détails de connexion dans le code testé.
- Exécutez localement et en CI ; vérifiez la disponibilité de Docker et la vitesse.
Essentiels Testcontainers 2.x
- Les artefacts sont tous préfixés
testcontainers-:org.testcontainers:testcontainers-junit-jupiter,testcontainers-postgresql,testcontainers-mysql,testcontainers-kafka, etc. (1.x :junit-jupiter,postgresql). Le cœur resteorg.testcontainers:testcontainers. - Les classes de conteneur des modules ont été déplacées vers des packages par module, par exemple
org.testcontainers.postgresql.PostgreSQLContainer(1.x :org.testcontainers.containers.PostgreSQLContainer). Les classes de base (GenericContainer,Network,wait.strategy.*) restent sousorg.testcontainers.containers. - Les classes de conteneur des modules ne sont plus génériques :
PostgreSQLContainer, pasPostgreSQLContainer<?>. - Utilisez un BOM pour garder les versions alignées :
org.testcontainers:testcontainers-bom:2.0.5(vérifiez la version actuelle sur Maven Central). - Docker Compose : utilisez
ComposeContainer(Compose v2) ;DockerComposeContainerest toujours présent en 2.0.5 (API plus ancienne) ; préférezComposeContainer.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>2.0.5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.14</version>
<scope>test</scope>
</dependency>
</dependencies>
Gradle : testImplementation platform("org.testcontainers:testcontainers-bom:2.0.5"), puis les mêmes artefacts Testcontainers sans versions, plus testRuntimeOnly "org.postgresql:postgresql:42.7.14". Le module Testcontainers ne regroupe pas le driver JDBC ; omettez le driver explicite si le projet en dépend déjà (par exemple via le BOM de Spring Boot).
Test minimal
import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.postgresql.PostgreSQLContainer;
@Testcontainers
class CustomerStoreIT {
@Container
static final PostgreSQLContainer POSTGRES = new PostgreSQLContainer("postgres:17-alpine");
@Test
void connects() throws Exception {
try (var c = java.sql.DriverManager.getConnection(
POSTGRES.getJdbcUrl(), POSTGRES.getUsername(), POSTGRES.getPassword())) {
org.junit.jupiter.api.Assertions.assertTrue(c.isValid(2));
}
}
}
Épinglez toujours l'étiquette d'image (jamais latest) ; faites correspondre la version majeure de production.
Décision du cycle de vie
| Besoin | Pattern |
|---|---|
| Un conteneur par classe de test | champ static @Container |
| Conteneur frais par méthode de test (lent, isolation forte) | champ @Container non-static |
| Un conteneur pour toute l'exécution de test (plus rapide) | singleton holder, voir references/lifecycle-and-reuse.md |
| Conserver les conteneurs entre les exécutions locales | withReuse(true) + propriété opt-in, local uniquement |
Préférez partager un conteneur et isoler les données (truncate/rollback, schéma unique ou BD par test) plutôt que de redémarrer les conteneurs.
Checklist
- [ ] Étiquette d'image épinglée et correspond à la production.
- [ ] Stratégie d'attente significative (les défauts des modules sont généralement corrects ; personnalisez pour
GenericContainer). - [ ] Aucun port d'hôte fixe ; utilisez
getMappedPort/getHost. - [ ] Conteneurs partagés entre les classes autant que possible (singleton).
- [ ] Tests d'intégration nommés
*ITet exécutés par failsafe (Maven) ou une tâche de test Gradle séparée, pour que les tests unitaires restent rapides. - [ ] Aucun secret ou identifiant réel dans les conteneurs de test.
- [ ] Le runner CI dispose de Docker ; la sortie est capturée en cas d'échec.
Références
references/lifecycle-and-reuse.md: par-classe/par-méthode, pattern singleton, réutilisation, exécutions parallèles, isolation des données.references/containers-and-waiting.md: modules vsGenericContainer, stratégies d'attente, env/config, scripts d'init, copie de fichiers, réseaux, configurations multi-conteneurs, Docker Compose.references/environment-ci-troubleshooting.md: configuration Docker/Podman/Colima, CI, registres privés, performance, erreurs courantes, tableau de migration 1.x vers 2.x.
Documentation officielle : https://java.testcontainers.org/
Migration vers 2.x : aucune page de migration dédiée n'a été trouvée sur java.testcontainers.org ; lisez les notes de version 2.0.0 https://github.com/testcontainers/testcontainers-java/releases/tag/2.0.0 et toutes les versions https://github.com/testcontainers/testcontainers-java/releases pour la version cible, et préférez-les à cette skill en cas de conflit.