Article écrit par Mouloud Haouili
Intégration des tests Spring Boot avec Testcontainers (PostgreSQL)
Testcontainers est une bibliothèque de test qui fournit des interfaces simples et légères pour exécuter des tests d’intégration avec des services réels encapsulés dans des conteneurs Docker. Cette solution permet d’écrire des tests interagissant avec les mêmes types de services déployés en production, éliminant ainsi le besoin de simulations ou de services en mémoire.
Un peu de contexte avant de commencer
Spring Boot est actuellement le framework le plus populaire pour le développement d’applications rapides dans le secteur du logiciel. Il permet une intégration facile de différentes bases de données, systèmes de messagerie, fournisseurs de cache, et de nombreux autres services tiers. L’un des services les plus répandus est Spring Data JPA, qui fournit une méthode directe pour élaborer des requêtes de base de données et les évaluer. Dans cet article, nous allons créer une petite application CRUD Spring Boot et mettre en place un environnement de test basé sur Testcontainers.
Le problème / Cas d’usage
Pour tester nos repositories Spring Data, nous pouvons simuler les données et tester les API, ou utiliser une base de données en mémoire (comme la base H2 que Spring Boot intègre facilement). Cependant, celle-ci pourrait ne pas correspondre à la base de données utilisée en production. Nos tests d’intégration ne garantiraient pas alors que notre code fonctionne correctement dans d’autres environnements. Monter une base de données de test distincte engendre des coûts opérationnels et financiers supplémentaires.
Testcontainers à la rescousse
Testcontainers, un projet open-source lancé en 2015, a gagné en popularité pour sa capacité à simplifier les tests d’intégration en fournissant des environnements de test légers et éphémères via des conteneurs Docker. Testcontainers évite de mocker des services ou de configurer des environnements compliqués, permettant de définir les dépendances nécessaires pour nos tests directement dans le code.
Prérequis
- Java: 17+
- Spring Boot: 3.1.x
- Un environnement Docker supporté par Testcontainers (https://java.testcontainers.org/supported_docker_environment/)
Nous allons créer une application Spring Boot en utilisant “Spring Initializr” et sélectionner les dépendances Spring Web, Spring Data JPA, PostgreSQL Driver, et Testcontainers starters. Pour simplifier, nous allons créer un contrôleur, un service et une classe repository pour créer et chercher un utilisateur par son nom.
- pom.xml
- UtilisateurController
- UtilisateurService
- UtilisateurRepository
- L’entité Utilisateur
- Le fichier de configuration application.properties
Pour l’instant rien d’impressionnant, mais passons à l’écriture de nos cas de tests.
- Nous testons d’abord notre repository :
@TestContainers :L’extension @Testcontainers
active le démarrage et l’arrêt automatiques de conteneurs Docker, ici un conteneur PostgreSQL, utilisés dans les tests. Le conteneur PostgreSQL est déclaré comme un champ statique avec l’annotation @Container
, ce qui signifie qu’il sera partagé entre toutes les méthodes de test de cette classe. Ce conteneur sera démarré une seule fois avant l’exécution de la première méthode de test (@BeforeAll
) et arrêté après l’exécution de la dernière méthode de test (@AfterAll
).
@Container :Dans un contexte de Testcontainers, l’annotation @Container
est utilisée pour :
- Marquer et identifier les conteneurs Docker dans les classes de test JUnit.
- Gérer automatiquement le démarrage et l’arrêt de ces conteneurs, assurant que chaque test s’exécute dans un environnement isolé et contrôlé.
- Faciliter la configuration et l’utilisation de conteneurs Docker pour les tests d’intégration.
@DynamicPropertySource :Est utilisée pour intégrer des propriétés dynamiques nécessaires pour configurer la connexion à une base de données PostgreSQL gérée par Testcontainers. Les propriétés ajoutées via @DynamicPropertySource
sont automatiquement prises en compte par Spring Boot dans notre test.
@BeforeAll et @AfterAll :@BeforeAll
est utilisé pour exécuter une méthode avant tous les tests de la classe, et @AfterAll
est utilisé pour exécuter une méthode après tous les tests de la classe.
@BeforeEach :Est utilisé pour signaler que la méthode annotée doit être exécutée avant chaque test de la classe.
D’autres annotations comme @AfterEach
, @BeforeAll
, @AfterAll
, @Test
, @RepeatedTest
, @TestFactory
, @TestTemplate
, etc., existent et peuvent correspondre à des cas d’usage variés. Plus d’informations sont disponibles ici : JUnit 5 Annotations.
Voyons maintenant comment tester la création et la recherche d’un utilisateur :
Ces exemples illustrent comment Testcontainers facilite la phase de test. Nous avons simplement injecté notre repository, qui interagit avec la base PostgreSQL initiée auparavant, et sauvegarde réellement un utilisateur. Les assertions confirment la réussite des tests.
- Nous testons à présent les méthodes du controller :
UtilisateurControllerTest
reprend la même logique en créant un conteneur PostgreSQL, puis le démarrant avant les tests et l’arrêtant après.
@SpringBootTestPeut être spécifiée sur une classe de test qui exécute des tests basés sur Spring Boot.
@SpringBootTest.WebEnvironment.RANDOM_PORTIndique à Spring Boot de démarrer l’application sur un port disponible choisi aléatoirement.
Nous utilisons TestRestTemplate pour tester des API. Plus de détails sont disponibles ici : TestRestTemplate.
L’implémentation de deux méthodes est présentée :
- Test de sauvegarde d’un utilisateur (API POST) :
Nous utilisons postForEntity
de TestRestTemplate pour créer l’utilisateur et récupérer un ResponseEntity
.
- Test de recherche d’un Utilisateur par son Id :
Nous utilisons la méthode getForEntity
de TestRestTemplate pour rechercher un utilisateur par son Id, puis on verifie que la reponse correspond au resultat attendu.
Pour résumer
Nous avons axé notre présentation sur une démonstration élégante pour les tests d’intégration en encapsulant notre service de base de données dans un conteneur Docker, mais TestContainers ne se limite pas à cela. TestContainers facilite la création d’un environnement de test fidèle à la production en permettant la conteneurisation de plus de 50 modules (pratiquement toutes les technologies qu’on peut dockeriser). Cette fidélité est cruciale pour garantir que les tests d’intégration reflètent le comportement réel de l’application dans un environnement de production. Cet outil, en éliminant la complexité et les incertitudes liées à la configuration des environnements de test, permet aux développeurs de se concentrer sur ce qui compte vraiment : écrire un code de haute qualité qui fonctionne aussi bien en test qu’en production.
Sources
- Getting Started with Testcontainers
- JUnit 5 Annotations
- Younup
- IBM Community
- Baeldung on JUnit 5 Test Order
- Mkyong on Spring Boot Testcontainers
Code source
Contact
Contactez-moi sur LinkedIn ou par mail à mouloud.haouili@ouidou.fr pour toute question.
Vous vous demandez qui est Ouidou ? N’hésitez pas à nous contacter via contact@ouidou.fr ou visiter notre site https://ouidou.fr