Introduction
Les tests d'intégration jouent un rôle crucial dans le développement logiciel moderne. Cependant, les tests avec des mocks ou des services en mémoire peuvent ne pas représenter fidèlement les environnements de production, entraînant des bugs inattendus. C'est là que Testcontainers entre en jeu.
Pourquoi avons-nous besoin de Testcontainers ?
Les Défis des Tests Traditionnels
Les tests traditionnels avec des mocks ou des services en mémoire présentent plusieurs limitations, notamment :
- Incapacité à simuler des environnements de production réels
- Fonctionnalités sous-jacentes différentes
- Difficulté à identifier les bugs en environnement de développement
Les Avantages de Testcontainers
Testcontainers permet d'exécuter des tests d'intégration avec des services réels en utilisant des conteneurs Docker, ce qui :
- Offre un environnement de test plus proche de la production
- Réduit les bugs en production
- Améliore la fiabilité des tests
Prérequis pour Réaliser ce TP
Prérequis Techniques
- JDK : Utilisez le JDK 21.0.1 ou une version ultérieure. Téléchargez-le ici.
- Maven : Utilisez Maven 3.9.7, la dernière version stable. Téléchargez-le ici.
- Docker : Utilisez Docker Engine 24.0.9, la dernière version stable. Téléchargez-le ici.
Prérequis de Connaissances
- Java
- Spring Boot
- JUnit
- Docker
Installation des Dépendances
Ajoutez les dépendances suivantes à votre fichier pom.xml
pour Testcontainers :
xml<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<version>1.19.8</version> <!-- Utilisez la dernière version de Testcontainers -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.19.8</version> <!-- Assurez-vous que cette version correspond à celle de Testcontainers -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.19.8</version> <!-- Utilisez la version de PostgreSQL correspondante -->
<scope>test</scope>
</dependency>
Cas de Test
Dans l'exemple ci-dessous, nous essayons de tester une API Rest qui crée et récupère les détails des étudiants. La base de données utilisée pour stocker les données des étudiants est PostgreSQL. Avant de commencer, assurez-vous que Docker est en cours d'exécution.
java@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
public class StudentControllerTest {
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private StudentRepository studentRepository;
@Container
static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:15-alpine");
@Test
public void testAddNewStudent() {
// Given
Student student = new Student();
student.setName("Alice");
student.setDateOfBirth("02/02/2021");
student.setGrade("II");
// When
ResponseEntity<Student> studentResponseEntity = restTemplate.
postForEntity("/students", student, Student.class);
// Then
Student savedStudent = studentResponseEntity.getBody();
assertEquals(HttpStatus.OK, studentResponseEntity.getStatusCode());
assertNotNull(savedStudent);
}
@Test
public void testFetchStudentById() {
// Given
Student student = new Student();
student.setName("Bob");
student.setDateOfBirth("03/03/2022");
student.setGrade("III");
studentRepository.save(student);
// When
ResponseEntity<Student> studentResponseEntity = restTemplate.
getForEntity("/students/" + student.getId(), Student.class);
// Then
Student studentResponse = studentResponseEntity.getBody();
assertEquals(HttpStatus.OK, studentResponseEntity.getStatusCode());
assertNotNull(studentResponse);
assertEquals(1, studentResponse.getId());
assertEquals(student.getName(), studentResponse.getName());
assertEquals(student.getDateOfBirth(), studentResponse.getDateOfBirth());
assertEquals(student.getGrade(), studentResponse.getGrade());
}
}
Exécution des Tests
Avant d'exécuter les tests, assurez-vous que Docker est en cours d'exécution. Utilisez ensuite la commande suivante dans le répertoire racine de votre projet :
bash./mvnw test
Annotations et Classes Importantes
- SpringBootTest : Crée un ApplicationContext et exécute l'environnement web entier utilisé pour le test.
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT : Un port disponible est choisi au hasard chaque fois que le test est exécuté.
- Testcontainers et Containers : Utilisés pour gérer le cycle de vie de démarrage et d'arrêt des conteneurs.
- TestRestTemplate : De Spring, utilisé pour appeler et tester les points de terminaison REST à travers les cas de test.
- ServiceConnection : Introduit dans SpringBoot 3.1, utilisé pour enregistrer la connexion de la base de données dans le conteneur au lieu de la mentionner manuellement en utilisant l'annotation DynamicPropertySource.
- PostgreSQLContainer<>("postgres:15-alpine") : Télécharge la version 15 de PostgreSQL basée sur Alpine Linux comme image de base lorsque le conteneur se lance.
Conclusion
En utilisant Testcontainers, vous pouvez améliorer la fiabilité de vos tests d'intégration en exécutant des services réels dans des conteneurs Docker, créant ainsi un environnement de test plus proche de la production. Cela permet de réduire les bugs qui peuvent survenir en production en s'assurant que vos tests sont exécutés dans un environnement similaire. Testcontainers offre une solution puissante pour tester les intégrations avec des services réels, éliminant les limitations des mocks ou des services en mémoire, et contribuant à une meilleure qualité globale du logiciel. Essayez Testcontainers dans vos projets pour découvrir ses avantages par vous-même.
@DataJpaTest and Repository Class in JUnit | Baeldung
Configuring Separate Spring DataSource for Tests | Baeldung