Testcontainers permet de faire ce genre de choses de façon automatique. Pour cela, il vous faudra les dépendances suivantes :
Côté code et afin de vous démontrer les deux façons de faire, j’utilise un profile (“testpg”) et un fichier application-testpg.yml contenant la configuration suivante :
Au niveau du code (lien Gitlab), rien de spécifique, on active simplement le profil en question. Hormis les annotations, le reste du code est complètement identique au test H2.
Lors de l’exécution du test, le framework va se servir de Docker pour récupérer une image Postgres et la démarrer. Vous devriez voir passer des logs de ce type :
2018-06-03 12:44:15.992 INFO 71125 --- [main] ???? [postgres:9.6.8] : Creating container for image: postgres:9.6.8 2018-06-03 12:44:16.153 INFO 71125 --- [main] ???? [postgres:9.6.8] : Starting container with ID: ea2d833e843ef8adc78da779e6b3c62b31e4c1fe8bf851ed82f1bae23f86d0c8 2018-06-03 12:44:16.629 INFO 71125 --- [main] ???? [postgres:9.6.8] : Container postgres:9.6.8 is starting: ea2d833e843ef8adc78da779e6b3c62b31e4c1fe8bf851ed82f1bae23f86d0c8 2018-06-03 12:44:21.361 INFO 71125 --- [main] ???? [postgres:9.6.8] : Container postgres:9.6.8 started
L’exécution est un peu plus lente – 600 ms (une fois l’image téléchargée) contre 400 ms pour le test avec H2 – mais cela reste raisonnable si utiliser une base mémoire n’est pas envisageable dans votre contexte.
Concernant le client HTTP, le problème est le même : nous ne voulons pas requêter le vrai service pour ne pas subir les éventuels problèmes de latence, d’indisponibilité ou de comportements non souhaités. Pour remédier à cela, nous utiliserons Wiremock qui permet de fournir des stubs pour des appels HTTP.
WireMock est configuré au travers d’une règle JUnit puis utilisé pour créer un stub de l’url qui nous intéresse. On peut simuler toutes sortes de choses (aussi bien au niveau de la requête que de la réponse) et notamment le corps de la réponse (ici depuis un fichier situé dans src/main/resources/__files/). Ci-dessous le code (lien Gitlab) :
Remarque : Si vous utilisez uniquement l’annotation @SpringBootTest
sans paramètre, Spring va instancier tout le contexte (en se basant sur la classe annoté @SpringBootApplication
). Il va notamment auto-configurer la base de données (datasource, entityManager, ...), ce qui, dans le cas du test de client, est contre-performant. Pour éviter cela, nous sélectionnons précisément les classes qui nous intéressent et en complément, nous choisissons les éléments d’AutoConfiguration utiles pour le test (grâce à @ImportAutoConfiguration
). Cela peut paraître verbeux et compliqué, voire superflu pour quelques tests, mais quand vous aurez plusieurs dizaines ou centaines de tests, c’est en minutes que vous compterez le temps perdu.
Malheureusement, le problème avec ce type de test c’est qu’il continuera de fonctionner le jour où l’API changera d’interface, wiremock faisant son travail de doublure à la perfection. Pour remédier à cela on peut faire des tests d’intégration, mais on tombe dans le travers inverse : dès que l’API ne sera pas disponible, le test échouera. Les tests de contrats vont nous permettre de répondre à cette problématique et nous verrons comment dans le prochain article.