Test d'intégration avec Maven

1. Vue d'ensemble

Maven est l'outil de construction le plus populaire dans l'espace Java, tandis que les tests d'intégration sont une partie essentielle du processus de développement. Par conséquent, il est naturel de configurer et d'exécuter des tests d'intégration avec Maven.

Dans ce didacticiel, nous allons passer en revue un certain nombre de manières différentes d'utiliser Maven pour les tests d'intégration et de séparer les tests d'intégration des tests unitaires.

2. Préparation

Pour rendre le code de démonstration proche d'un projet du monde réel, nous allons configurer une application JAX-RS. Cette application est déployée sur un serveur avant l'exécution des tests d'intégration et démontée par la suite.

2.1. Configuration Maven

Nous allons construire notre application REST autour de Jersey - l'implémentation de référence de JAX-RS. Cette implémentation nécessite quelques dépendances:

 org.glassfish.jersey.containers jersey-container-servlet-core 2.27   org.glassfish.jersey.inject jersey-hk2 2.27 

Nous pouvons trouver les dernières versions de ces dépendances ici et ici.

Nous utiliserons le plugin Jetty Maven pour mettre en place un environnement de test. Ce plugin démarre un serveur Jetty pendant la phase de test de pré-intégration du cycle de vie de construction de Maven, puis l'arrête dans la phase de test de post-intégration .

Voici comment nous configurons le plugin Jetty Maven dans pom.xml :

 org.eclipse.jetty jetty-maven-plugin 9.4.11.v20180605   8999  quit 9000    start-jetty pre-integration-test  start    stop-jetty post-integration-test  stop    

Lorsque le serveur Jetty démarre, il écoute sur le port 8999 . Les éléments de configuration stopKey et stopPort sont utilisés uniquement par l' objectif d' arrêt du plugin et leur valeur n'est pas importante de notre point de vue.

Voici où trouver la dernière version du plugin Jetty Maven.

Une autre chose à noter est que nous devons définir l' élément d' empaquetage dans le fichier pom.xml sur war , sinon le plugin Jetty ne peut pas démarrer le serveur:

war

2.2. Créer une application REST

Le point de terminaison de l'application est très simple: renvoyer un message de bienvenue lorsqu'une requête GET atteint la racine du contexte:

@Path("/") public class RestEndpoint { @GET public String hello() { return "Welcome to Baeldung!"; } }

Voici comment nous enregistrons la classe de point de terminaison avec Jersey:

package com.baeldung.maven.it; import org.glassfish.jersey.server.ResourceConfig; public class EndpointConfig extends ResourceConfig { public EndpointConfig() { register(RestEndpoint.class); } }

Pour que le serveur Jetty connaisse notre application REST, nous pouvons utiliser un descripteur de déploiement web.xml classique :

  rest-servlet org.glassfish.jersey.servlet.ServletContainer  javax.ws.rs.Application com.baeldung.maven.it.EndpointConfig    rest-servlet /*  

Ce descripteur doit être placé dans le répertoire / src / main / webapp / WEB-INF pour être reconnu par le serveur.

2.3. Code de test côté client

Toutes les classes de test des sections suivantes contiennent une seule méthode:

@Test public void whenSendingGet_thenMessageIsReturned() throws IOException { String url = "//localhost:8999"; URLConnection connection = new URL(url).openConnection(); try (InputStream response = connection.getInputStream(); Scanner scanner = new Scanner(response)) { String responseBody = scanner.nextLine(); assertEquals("Welcome to Baeldung!", responseBody); } }

Comme nous pouvons le voir, cette méthode ne fait rien d'autre que d'envoyer une requête GET à l'application Web que nous avons configurée auparavant et de vérifier la réponse.

3. Tests d'intégration en action

Une chose importante à noter à propos des tests d'intégration est que les méthodes de test prennent souvent beaucoup de temps à s'exécuter.

Par conséquent, nous devons exclure les tests d'intégration du cycle de vie de construction par défaut, en les empêchant de ralentir l'ensemble du processus chaque fois que nous construisons un projet.

Un moyen pratique de séparer les tests d'intégration consiste à utiliser des profils de génération. Ce type de configuration nous permet d'exécuter des tests d'intégration uniquement lorsque cela est nécessaire - en spécifiant un profil approprié.

Dans les sections qui suivent, nous allons configurer tous les tests d'intégration avec des profils de build.

4. Test avec le plugin Failsafe

Le moyen le plus simple d'exécuter des tests d'intégration consiste à utiliser le plugin de sécurité Maven .

Par défaut, le plugin Maven surefire exécute des tests unitaires pendant la phase de test , tandis que le plugin de sécurité exécute des tests d'intégration dans la phase de test d'intégration .

Nous pouvons nommer des classes de test avec différents modèles pour ces plugins afin de récupérer les tests inclus séparément.

Les conventions de nommage par défaut appliquées par surefire et failsafe sont différents, donc nous avons juste besoin de suivre ces conventions à l' unité et les tests d' intégration Séparer les .

L'exécution du plugin surefire inclut toutes les classes dont le nom commence par Test , ou se termine par Test , Tests ou TestCase . En revanche, le plugin de sécurité exécute des méthodes de test dans des classes dont le nom commence par IT ou se termine par IT ou ITCase .

C'est là que nous pouvons trouver la documentation concernant l'inclusion de test pour surefire , et voici celle pour la sécurité .

Ajoutons le plugin de sécurité au POM avec la configuration par défaut:

 failsafe    maven-failsafe-plugin 2.22.0    integration-test verify       

Ce lien est l'endroit où trouver la dernière version du plugin de sécurité .

With the above configuration, the following test method will be executed in the integration-test phase:

public class RestIT { // test method shown in subsection 2.3 }

Since the Jetty server starts up in the pre-integration-test phase and shuts down in post-integration-test, the test we have just seen passes with this command:

mvn verify -Pfailsafe

We can also customize the naming patterns to include classes with different names:

 maven-failsafe-plugin 2.22.0   **/*RestIT **/RestITCase   ... 

5. Testing With the Surefire Plugin

Apart from the failsafe plugin, we can also use the surefire plugin to execute unit and integration tests in different phases.

Let's assume we want to name all integration tests with the suffix IntegrationTest. Since the surefire plugin runs tests with such a name in the test phase by default, we need to exclude them from the default execution:

 maven-surefire-plugin 2.22.0   **/*IntegrationTest   

The latest version of this plugin is here.

We've taken all test classes having a name ending with IntegrationTest out of the build lifecycle. It's time to put them back with a profile:

 surefire    maven-surefire-plugin 2.22.0   integration-test  test    none   **/*IntegrationTest        

Instead of binding the test goal of the surefire plugin to the test build phase, as usual, we bound it to the integration-test phase. The plugin will then kick in during the integration testing process.

Notice that we must set an exclude element to none to override the exclusion specified in the base configuration.

Now, let's define an integration test class with our naming pattern:

public class RestIntegrationTest { // test method shown in subsection 2.3 }

This test will be running with the command:

mvn verify -Psurefire

6. Testing With the Cargo Plugin

We can use the surefire plugin with the Maven cargo plugin. This plugin comes with built-in support for embedded servers, which are very useful for integration testing.

More details about this combination can be found here.

7. Testing With JUnit's @Category

A convenient way to selectively execute tests is to leverage the @Category annotation in the JUnit 4 framework. This annotation lets us exclude particular tests from unit testing, and include them in integration testing.

First off, we need an interface or class to work as a category identifier:

package com.baeldung.maven.it; public interface Integration { }

We can then decorate a test class with the @Category annotation and Integration identifier:

@Category(Integration.class) public class RestJUnitTest { // test method shown in subsection 2.3 }

Rather than declaring the @Category annotation on a test class, we can also use it at the method level to categorize individual test methods.

Excluding a category from the test build phase is simple:

 maven-surefire-plugin 2.22.0  com.baeldung.maven.it.Integration  

Including the Integration category in the integration-test phase is also straightforward:

 category    maven-failsafe-plugin 2.22.0   **/*  com.baeldung.maven.it.Integration     integration-test verify       

We can now run integration tests with a Maven command:

mvn verify -Pcategory

8. Adding a Separate Directory for Integration Tests

It's desirable at times to have a separate directory for integration tests. Organizing tests this way allows us to entirely isolate integration tests from unit tests.

We can use the Maven build helper plugin for this purpose:

 org.codehaus.mojo build-helper-maven-plugin 3.0.0   add-integration-test-source generate-test-sources  add-test-source    src/integration-test/java     

Here is where we can find the latest version of this plugin.

The configuration we've just seen adds a test source directory to the build. Let's add a class definition to that new directory:

public class RestITCase { // test method shown in subsection 2.3 }

It's time to run integration tests in this class:

mvn verify -Pfailsafe

Le plugin de sécurité Maven exécutera les méthodes de cette classe de test en raison de la configuration définie dans la sous-section 3.1.

Un répertoire source de test va souvent avec un répertoire de ressources. Nous pouvons ajouter un tel répertoire dans un autre élément d' exécution de la configuration du plugin:

 ...  add-integration-test-resource generate-test-resources  add-test-resource     src/integration-test/resources     

9. Conclusion

Cet article a décrit l'utilisation de Maven pour exécuter des tests d'intégration avec un serveur Jetty, en se concentrant sur la configuration des plugins Maven infaillible et infaillible .

Le code source complet de ce didacticiel se trouve à l'adresse over sur GitHub.