- Avoir des notions sur l'environnement Java (Maven et Spring boot).
- Avoir des notions de Docker.
- Java 17, Docker et Maven installé sur la machine (version maven utilisée : 3.9.3).
Sur ce tutoriel, nous vous présenterons TestContainers, une solution élégante pour écrire vos tests d'intégration sous un environnement Java, et pourquoi vous devriez l’inclure sur vos actuels ou futurs projets.
Historiquement, écrire des tests d'intégration interagissant avec une base de données était une tâche ardue, la solution la plus répandue était d'implémenter une base de données en mémoire (exemple : H2) pour exécuter les tests d'intégration dans un environnement propre à eux.
Or, cette démarche présente quelques désavantages :
● Fiabilité des tests : Un environnement de production utilisera très rarement une base de données en mémoire, et ceci pour des besoins de durabilité, précision d’information et de consistance (1), et donc une base de données de production (exemple : Postgresql ou MS SQL Server) seront plébiscités, or dans ce cas on commence à observer un comportement différent de notre solution entre la base de données en mémoire et la base de données de production. Il n’est pas rare d’avoir des scénarios de tests qui s'exécutent correctement sur l'environnement de tests, et qui plantent sur l'environnement de production (2).
● Absence de fonctionnalités : Dans le cas où les bases de données possèdent des fonctionnalités exclusives propres à eux, la testabilité de ces dites fonctionnalités peut s'avérer très compliquée voire impossible avec une base de données en mémoire (2).
● Maintenabilité des tests : Même si certaines bases de données en mémoire se rapproche dans leurs comportements d’une base de données réelle (une base de données en mémoire tel que H2 est compatible avec beaucoup de bases de données) (3), il n’est pas rare qu’une solution opère une migration d’une base de données à une autre pour des besoins de performances ou de sécurité. Or dans ce cas présent, l’absence de couverture de tests sur des fonctionnalités critiques peut amener à une migration complexe.
TestContainers a été pensé pour répondre aux problématiques présentées ci-dessus.
Sur la documentation officielle, Testcontainers est défini comme suit :
“Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.”
Au départ Testcontainers avait pour objectif de résoudre le problème de l’instanciation de la base de données lors du lancement des tests d'intégration, et au fil de son succès, la librairie s’est ouverte à d’autres langages de programmation (C#, Javascript, Go …) et d’autres modules pour des implémentations de tests différents : (Bases de données NoSQL, SSO tel que Keycloak, un service de bus de messages tel que Kafka…).
Aussi, TestContainers répond à la problématique de la fiabilité de tests en exécutant ces derniers dans un conteneur Docker.
En spécifiant l’image de base, l'environnement de test sera similaire à l'environnement de production, de même pour les fonctionnalités des différentes bases données ainsi que la maintenabilité des différents tests d'intégration.
Dans l’application, Testcontainers a une logique assez simple pour exécuter les tests d'intégrations :
- Initier un conteneur Docker avec l’image voulue.
- Lancer le conteneur.
- Lancer l’application à l’intérieur du conteneur.
- Exécuter les tests d'intégration.
- Arrêter le conteneur.
Vous l'aurez compris, ces tests s'exécutent automatiquement dans un environnement isolé que nous avons nous même choisi. Grâce à Docker, ces tests peuvent aussi s'exécuter sur une chaîne d'intégration continue.
En ce qui concerne les désavantages de TestContainers, j’ai pu observer un temps d'exécution plus lent que des tests exécutés sur des bases de données en mémoire, ceci peut se traduire par des temps de build et tests plus longs. Ce point reste important à mentionner.
Assez de théorie, place à la pratique.
Tout d’abord, créer un projet Spring boot sous intellij :
Sur spring intializer, sélectionner les dépendances suivantes :
Puis télécharger le fichier compressé ZIP et ouvrez le sur votre ordinateur.
Sur votre POM.xml, vous trouverez les dépendances sélectionnées précédemment, puis ajoutez cette dépendance :
Notre application est prête pour être lancée, sauf qu’elle ne contient rien actuellement.
Ce que nous allons faire, c’est de créer une simple API qui a pour but d’enregistrer des étudiants, avec une seule condition : ils doivent être âgés entre 18 et 28 ans pour prétendre être étudiant, sinon ils seront informés que leur âge n’est pas conforme à la catégorie étudiant.
Pour cela, nous allons créer un Rest endpoint pour accomplir cette tâche.
Créons d’abord une entité étudiant :
Puis un repository
Une méthode dans notre service qui contient la logique de notre API :
Et enfin notre API dans notre contrôleur :
Notre API est prête, nous pouvons la tester avec un test d'intégration qui va s’assurer de :
- Création de l’entité.
- Vérification de lacondition d'âge.
- Exécution d’une requêteSQL pour l’ajout à notre base de données.
Avant de pouvoir commencer à écrire nos tests, TestContainers a besoin d’une config pour exécuter les tests :
La configuration suivante permet de créer un contexte de test avec une image de base de données postgres, et de spécifier différentes informations (username, password, URL).
S’en suit l’écriture d’un test paramétré pour tester notre API :
Ce test permet à la fois de vérifier que les étudiants avec le bon âge soient ajoutés à la base de données, et ceux possédant le mauvais âge ne le soient pas, et donc une exception doit être renvoyée pour informer l’utilisateur que l'âge ne correspond pas à la catégorie étudiant.
On s'aperçoit aussi que la complexité a été fortement réduite, et que les tests sont plus légers.
Aussi, on remarque que nous n'avons même pas besoin de lancer l’application et de tester l’API sur une application externe (ex : Postman), cette bibliothèque nous ouvre la porte pour tester nos APIs sans avoir à quitter notre éditeur de code.
Sur ce tutoriel, nous avons pu voir la force de la bibliothèque testContainers et comment mettre en place un environnement pour exécuter des tests d'intégrations. Vous pourrez trouver ci-dessous en détails la documentation ainsi que le code source utilisé lors de cet article.
Le code source : https://github.com/abderrezakBoukazouha/Integration-tests-testContainers/blob/main/pom.xml
Sources:
1. https://www.dragonflydb.io/faq/advantages-and-disadvantages-of-in-memory-database
2. https://phauer.com/2017/dont-use-in-memory-databases-tests-h2/
3. https://www.h2database.com/html/features.html - section SQL Support