Il y a 9 ans -
Temps de lecture 4 minutes
Séparer les tests d’intégration avec Maven
Lors de nos développements, il est bien pratique de pouvoir lancer les tests unitaires sans lancer les (longs) tests d’intégration.
Dans un projet Maven, les tests unitaires et d’intégration sont traditionnellement placés sous le répertoire src/test/java
:
src/main/java/ ╰─ com ╰─ xebia ╰─ project ╰─ MyComponent.java src/test/java/ ╰─ com ╰─ xebia ╰─ project ╰─ MyComponentTest.java ╰─ MyComponentITest.java
C’est la solution la plus simple. L’avantage étant que les tests (unitaires et d’intégration) peuvent ainsi respecter l’arborescence des packages du main
.
Cependant, du point de vue arborescence de fichiers, il n’y a pas de séparation nette entre tests unitaires et tests d’intégration.
De plus, il devient difficile de lancer les tests unitaires (par exemple avant un commit) sans lancer les tests d’intégration. S’il est vrai que Maven fournit la possibilité d’exclure des tests en se basant sur une expression (par exemple tous les *ITest.java
) via le plugin failsafe
lors d’un mvn test
, c’est toutefois plus difficile (voire impossible) à obtenir en utilisant les outils intégrés aux IDE (comme Eclipse) quand on veut lancer tous les tests unitaires ensemble (« Run as Junit test » sur un dossier). Or, pour les développeurs il est nécessaire de pouvoir passer les tests unitaires avant chaque commit, sans avoir à passer également les tests d’intégrations qui peuvent prendre de plusieurs minutes à plusieurs heures pour s’exécuter. Si certains IDE (comme IntelliJ) permettent d’exclure des tests en se basant sur une expression rationnelle, cela oblige à figer le nom desdits tests, par exemple en *Itest.java
.
Quelles solutions avons-nous à notre disposition pour résoudre ce problème ?
Placer les tests d’intégration dans un paquetage séparé
Il est possible, pour séparer nettement les tests unitaires et tests d’intégration, de placer ces derniers dans un package dédié :
src/main/java/ ╰─ com ╰─ xebia ╰─ project ╰─ MyComponent.java src/test/java/ ╰─ com ╰─ xebia ╰─ project ╰─ MyComponentTest.java ╰─ it ╰─ com ╰─ xebia ╰─ project ╰─ MyComponentITest.java
Avec cette solution, on obtient bien la séparation nette désirée entre classes de tests unitaires et classes de tests d’intégration. Toutefois, pour les tests d’intégration, on perd alors la possibilité de respecter l’arborescence des paquetages du main, avec ce que cela entraine (pas accès aux membres package-private et protected).
Placer les tests d’intégration dans un module séparé
C’est une solution qui a du sens dans le cas de tests d’intégration haut niveau (Selenium). Cependant l’expérience m’a prouvé qu’une fois que les tests d’intégration sont placés dans un module séparé du projet principal, personne ne télécharge ce module. Les tests d’intégration ne sont alors que peu ou plus maintenus (ne parlons pas d’en ajouter de nouveaux). En effet, cela fait deux fois plus de projets à gérer, ce qui est particulièrement pénible, par exemple, dans une architecture SOA où les développeurs travaillent déjà avec une myriade de projets différents dans leur espace de travail.
Placer les tests d’intégration dans un dossier réservé
Une solution idéale serait d’avoir un dossier spécifique pour les tests d’intégration, comme par exemple src/it/java
:
src/main/java/ ╰─ com ╰─ xebia ╰─ project ╰─ MyComponent.java src/test/java/ ╰─ com ╰─ xebia ╰─ project ╰─ MyComponentTest.java src/it/java/ ╰─ com ╰─ xebia ╰─ project ╰─ MyComponentITest.java
Cependant une telle arborescence ne respecte plus les conventions d’organisation de projet Maven, ce qui signifie que les tests placés dans src/it/java
ne seront pas lancés lors de la phase test
de la construction du projet. Mais il est possible de spécifier à Maven un (ou plusieurs) répertoires additionnels où chercher les tests. Ceci s’effectue grâce au plugin build-helper
. Pour ce faire, il faut ajouter dans la section build
du pom.xml
le code suivant :
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <executions> <execution> <id>add-test-source</id> <phase>process-resources</phase> <goals> <goal>add-test-source</goal> </goals> <configuration> <sources> <source>src/it/java</source> </sources> </configuration> </execution> </executions> </plugin>
Lorsque l’on observe l’intégration dans l’IDE Eclipse (ou d’autres), on constate qu’à présent, le répertoire src/it/java
est bien considéré par Maven comme un répertoire de sources, au même niveau que src/main/java
et src/test/java
:
Cette approche comble les faiblesses des solutions des sections précédentes procurant des avantages certains pour les tests d’intégration qui sont à présent :
- clairement séparés des tests unitaires, ce qui permet aux développeurs de lancer les tests unitaires facilement avec les outils de l’IDE (en dehors d’un
mvn test
) ; - qui ne sont pas forcés de porter un nom particulier (ex.
*ITest.java
) pour les distinguer des tests unitaires ; - avec une structure de test qui s’intègre dans le processus de build Maven ;
- respectueux de la structure de packages du
main
; - inclus dans le même module que le projet concerné.
Commentaire
7 réponses pour " Séparer les tests d’intégration avec Maven "
Published by JY , Il y a 9 ans
Une info bien utile qui deviendra j’espère la convention ! :)
Je n’ai jamais compris pourquoi Maven n’avait pas déjà « normaliser » la mise en oeuvre des tests d’intégrations … Dans Maven4 peut-être ;)
Published by nrichand , Il y a 9 ans
Amusant, un blog bien connu avait fait un article similaire exactement 4 ans jour pour jour ( http://bit.ly/1hQP7v9 ). Il semblerait que les choses aient peu évoluées depuis.
Au final je préfère depuis la convention *ITest et failsafe même s’il faut finter sous Eclipse (via infinitest par exemple) ou passer sur intelliJ. Quand on aime Maven on aime les conventions :p
Published by Bastien Bonnet , Il y a 9 ans
Salut Nathaniel. J’avais bien lu ton article (dont la portée est plus large que le mien), qui comporte des solutions alternatives intéressantes. Pour la date, c’est purement fortuit !
La difficulté de lancer les tests unitaires séparément sous certains EDI n’est pas la seule raison pour laquelle j’ai recherché une solution alternative :
– je n’aime pas avoir les tests d’intégration au même endroit que les tests unitaires ;
– je n’aime pas être contraint de choisir ma convention de nommage (ex. *ITest.java) pour faciliter le filtrage plus tard.
Published by Sylvain , Il y a 9 ans
Je trouve pour ma part que maven a déjà bien normalisé la notion des tests d’intégration. C’est une phase à part dans le build et il y a le plug-in maven-failsafe-plugin.
Si on respecte la convention de maven-failsafe-plugin pour nommer les tests d’intégration (**/IT*.java, **/*IT.java, **/*ITCase.java) alors « maven test » n’exécute que les tests unitaires et si on veux lancer les tests d’intégration on utilise « maven verify ». Pas de configuration spécial dans le pom, c’est par défaut.
Je concède que si on veut lancer via l’IDE, là, cette solution me semble plus élégante.
Published by Sebastien Lorber , Il y a 9 ans
On peut aussi utiliser l’annotation @Category si on utilise JUnit.
Dans mon ancienne équipe on utilisait ca avec « mvn clean install -Pit » avec une config spécifique du plugin surfire sur ce profil maven. Perso je trouve ça mieux que des regex et de toute facon il faut souvent un profil maven différent (par ex pour lancer un serveur jetty embedded pour tester une API)
Published by JY , Il y a 9 ans
(Add new element in the POM model)
-> https://jira.codehaus.org/browse/MNG-2009
Une feature à suivre sur le sujet pour Maven 4.0 ?
Published by Clément HELIOU , Il y a 9 ans
Bastien,
Je trouve votre solution relativement élégante et vous rejoins à propos des règles de nommage.
Je trouve que filtrer sur un nom de classe est bien peu robuste par rapport aux dérives possibles. A moins de vérifier à coup sûr le nom des classes de tests d’intégration…
Par ailleurs, et pour compléter ce que disait Sébastien, il existe un attribut « groups » dans l’annotation « @Test » de TestNG qui, couplée à l’usage de Surefire et d’un profil, permet d’exclure/inclure les tests d’intégration. J’en fais mention dans un article de mon blog (http://mister-tie.fr/blog/2013/07/24/testng-peut-il-detroner-junit-13/) où je compare JUnit @ TestNG.
Bien à vous.