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é.