1. Información general
Maven es la herramienta de compilación más popular en el espacio de Java, mientras que las pruebas de integración son una parte esencial del proceso de desarrollo. Por lo tanto, es una elección natural configurar y ejecutar pruebas de integración con Maven.
En este tutorial, repasaremos varias formas diferentes de usar Maven para las pruebas de integración y para separar las pruebas de integración de las pruebas unitarias.
2. Preparación
Para que el código de demostración se parezca a un proyecto del mundo real, configuraremos una aplicación JAX-RS. Esta aplicación se implementa en un servidor antes de la ejecución de las pruebas de integración y luego se desmantela.
2.1. Configuración de Maven
Construiremos nuestra aplicación REST alrededor de Jersey, la implementación de referencia de JAX-RS. Esta implementación requiere un par de dependencias:
org.glassfish.jersey.containers jersey-container-servlet-core 2.27 org.glassfish.jersey.inject jersey-hk2 2.27
Podemos encontrar las últimas versiones de estas dependencias aquí y aquí.
Usaremos el complemento Jetty Maven para configurar un entorno de prueba. Este complemento inicia un servidor Jetty durante la fase de prueba previa a la integración del ciclo de vida de la compilación de Maven y luego lo detiene en la fase de prueba posterior a la integración .
Así es como configuramos el complemento Jetty Maven en 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
Cuando se inicie el servidor Jetty, estará escuchando en el puerto 8999 . Los elementos de configuración stopKey y stopPort son utilizados únicamente por el objetivo de parada del complemento y su valor no es importante desde nuestra perspectiva.
Aquí es donde encontrar la última versión del complemento Jetty Maven.
Otra cosa a tener en cuenta es que debemos configurar el elemento de empaquetado en el archivo pom.xml en war , de lo contrario, el complemento Jetty no puede iniciar el servidor:
war
2.2. Creación de una aplicación REST
El punto final de la aplicación es muy simple: devolver un mensaje de bienvenida cuando una solicitud GET llega a la raíz del contexto:
@Path("/") public class RestEndpoint { @GET public String hello() { return "Welcome to Baeldung!"; } }
Así es como registramos la clase de punto final con Jersey:
package com.baeldung.maven.it; import org.glassfish.jersey.server.ResourceConfig; public class EndpointConfig extends ResourceConfig { public EndpointConfig() { register(RestEndpoint.class); } }
Para que el servidor Jetty conozca nuestra aplicación REST, podemos usar un descriptor de implementación web.xml clásico :
rest-servlet org.glassfish.jersey.servlet.ServletContainer javax.ws.rs.Application com.baeldung.maven.it.EndpointConfig rest-servlet /*
Este descriptor debe estar ubicado en el directorio / src / main / webapp / WEB-INF para ser reconocido por el servidor.
2.3. Código de prueba del lado del cliente
Todas las clases de prueba en las siguientes secciones contienen un solo método:
@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); } }
Como podemos ver, este método no hace más que enviar una solicitud GET a la aplicación web que configuramos antes y verificar la respuesta.
3. Pruebas de integración en acción
Un aspecto importante a tener en cuenta sobre las pruebas de integración es que los métodos de prueba suelen tardar bastante en ejecutarse.
Como resultado, deberíamos excluir las pruebas de integración del ciclo de vida de construcción predeterminado, evitando que ralenticen todo el proceso cada vez que construimos un proyecto.
Una forma conveniente de separar las pruebas de integración es utilizar perfiles de compilación. Este tipo de configuración nos permite ejecutar pruebas de integración solo cuando sea necesario, especificando un perfil adecuado.
En las secciones siguientes, configuraremos todas las pruebas de integración con perfiles de compilación.
4. Prueba con el complemento Failsafe
La forma más sencilla de ejecutar pruebas de integración es utilizar el complemento a prueba de fallos de Maven .
De forma predeterminada, el complemento surefire de Maven ejecuta pruebas unitarias durante la fase de prueba , mientras que el complemento a prueba de fallas ejecuta pruebas de integración en la fase de prueba de integración .
Podemos nombrar clases de prueba con diferentes patrones para que esos complementos recojan las pruebas adjuntas por separado.
Las convenciones de nomenclatura predeterminadas impuestas por surefire y failsafe son diferentes, por lo que solo necesitamos seguir estas convenciones para separar las pruebas de unidad y de integración.
La ejecución del complemento seguro incluye todas las clases cuyo nombre comienza con Test o termina con Test , Tests o TestCase . Por el contrario, el complemento a prueba de fallos ejecuta métodos de prueba en clases cuyo nombre comienza con IT o termina con IT o ITCase .
Aquí es donde podemos encontrar la documentación relacionada con la inclusión de pruebas para infalible , y aquí está la de seguridad .
Vamos a añadir la prueba de fallos plugin para el POM con la configuración por defecto:
failsafe maven-failsafe-plugin 2.22.0 integration-test verify
Este enlace es donde encontrar la última versión del complemento a prueba de fallas .
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
El complemento a prueba de fallos de Maven ejecutará métodos en esta clase de prueba debido a la configuración que establecimos en la subsección 3.1.
Un directorio de origen de prueba suele ir con un directorio de recursos. Podemos agregar dicho directorio en otro elemento de ejecución a la configuración del complemento:
... add-integration-test-resource generate-test-resources add-test-resource src/integration-test/resources
9. Conclusión
Este artículo repasó el uso de Maven para ejecutar pruebas de integración con un servidor Jetty, centrándose en la configuración de los complementos seguros y a prueba de fallos de Maven .
El código fuente completo de este tutorial se puede encontrar en GitHub.