maven tomcat junit maven-2 tomcat7

Maven: despliegue webapp en tomcat antes de la prueba de JUnit



maven-2 tomcat7 (3)

Tengo una aplicación web que brinda servicio web. Quiero realizar pruebas JUnit con SoapUI para verificar si este servicio funciona correctamente.
Pero para probar la aplicación del servicio web debe implementarse en mi servidor Tomcat 7.

No tengo idea de cómo configurar maven para construir war, luego implementarlo en tomcat (idealmente: para ejecutar una instancia de tomcat separada para esto) y luego ejecutar pruebas de JUnit.
Apreciaré cualquier ayuda.

Estoy usando maven 2.2.1


@Stephen Connolly: su respuesta anterior fue realmente buena. Pensé en dar un puntapié y mostrar una configuración completa para lo que denominó una respuesta de la School 1 .

Esta configuración:

  • ejecuta pruebas unitarias por separado de las pruebas de integración. Utiliza la anotación @Category en las clases raíz que las pruebas unitarias y las pruebas de integración amplían.
  • antes de las pruebas de integración, inicia la aplicación dependiente (cargada como una dependencia de maven en el tiempo de ejecución) en la máquina local, al encontrar un puerto abierto
  • después de las pruebas de integración, elimina la aplicación dependiente

Hay otras cosas allí, como por ejemplo cómo configurar ciertas propiedades del sistema solo en la aplicación dependiente.

Hasta ahora, esta configuración funciona de maravilla.

<build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>1.9.1</version> <executions> <execution> <id>reserve-network-port</id> <goals> <goal>reserve-network-port</goal> </goals> <phase>pre-integration-test</phase> <configuration> <portNames> <portName>tomcat.maven.http.port</portName> </portNames> </configuration> </execution> <execution> <id>get-local-ip</id> <goals> <goal>local-ip</goal> </goals> <configuration> <!-- if not given, ''local.ip'' name is used --> <localIpProperty>local.ip</localIpProperty> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <!-- http port from reserve-network-port-plugin--> <port>${tomcat.maven.http.port}</port> <!-- application path always starts with /--> <path>/</path> <webapps> <webapp> <groupId>com.company.other.app</groupId> <artifactId>web-rest</artifactId> <version>1.0.1-SNAPSHOT</version> <type>war</type> <contextPath>/webapi-loopback</contextPath> <asWebapp>true</asWebapp> </webapp> </webapps> </configuration> <executions> <execution> <id>start-server</id> <configuration> <fork>true</fork> <skip>${skipTests}</skip> <systemProperties> <spring.profiles.active>test,h2</spring.profiles.active> </systemProperties> </configuration> <phase>pre-integration-test</phase> <goals> <goal>run</goal> </goals> </execution> <execution> <id>stop-server</id> <configuration> <skip>${skipTests}</skip> </configuration> <phase>post-integration-test</phase> <goals> <goal>shutdown</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19</version> <configuration> <excludedGroups>com.company.app.service.IntegrationTestRootClassAnnotatedWithAtCategory</excludedGroups> </configuration> <executions> <execution> <id>unit-test</id> <phase>test</phase> <goals> <goal>test</goal> </goals> <configuration> <argLine>-Xmx1024m -XX:MaxPermSize=256m @{jacocoArgLine}</argLine> <excludedGroups> com.company.app.service.IntegrationTestRootClassAnnotatedWithAtCategory </excludedGroups> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>2.18</version> <dependencies> <dependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit47</artifactId> <version>2.18</version> </dependency> </dependencies> <executions> <execution> <id>start-integration-test</id> <phase>integration-test</phase> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> <configuration> <argLine>-Xmx1024m -XX:MaxPermSize=256m @{jacocoArgLine}</argLine> <groups>com.company.app.IntegrationTestRootClassAnnotatedWithAtCategory</groups> <includes> <include>**/*.java</include> </includes> <systemPropertyVariables> <program.service.url> http://${local.ip}:${tomcat.maven.http.port}/webapi-loopback </program.service.url> </systemPropertyVariables> </configuration> </execution> </executions> </plugin> </plugins> </build>


Como explica Stephen Connolly, no hay una forma directa de configurar esto. Explicaré cómo resolver esto usando el plugin de failsafe. En el ciclo de vida de maven se puede probar el tipo de prueba. Las pruebas unitarias de uno y otro son pruebas integradas. Las pruebas unitarias se pueden ejecutar en la etapa de prueba del ciclo de vida de maven. Cuando quiera hacer una prueba integrada, puede hacerlo en la etapa de verificación. Si desea saber la diferencia entre las pruebas unitarias y las pruebas integradas, esta es una buena opción . Por defecto, las clases de prueba unitarias deben estar en ***/*Test.java , y **/*TestCase.java este formato. El plugin **/IT*.java buscará **/IT*.java , **/*IT.java , y **/*ITCase.java .

Aquí hay un ejemplo.

Aquí tengo una clase de prueba de unidad y una clase de prueba integrada. Ahora voy a explicar, ¿cómo debería ser el aspecto como maven pom.xml. La sección de compilación de la configuración de maven debería verse así.

<build> <plugins> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <webXml>src/main/webapp/WEB-INF/web.xml</webXml> <warName>${name}</warName> <outputDirectory>/home/jobs/wso2/wso2as-5.3.0/repository/deployment/server/webapps</outputDirectory> <goal> </goal> </configuration> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>2.12.4</version> <executions> <execution> <id>integration-test</id> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> </plugin> </plugins>

Las pruebas unitarias se ejecutan antes de implementar la aplicación web (archivo war). Pero las pruebas integradas se ejecutan en la etapa de verificación. Espero que su requisito esté satisfecho en esta etapa.


Hay varias escuelas de pensamiento sobre cómo manejar este tipo de prueba de integración con Maven.

Debo señalar que cuando está implementando una aplicación en un servidor de aplicaciones, ya no está en el campo de las pruebas unitarias. Debido a que toda la aplicación se está implementando dentro de un contenedor, está probando la integración de esos dos componentes.

Ahora no tiene nada de malo utilizar JUnit para ejecutar pruebas de integración (aunque hay algunas limitaciones que puede aplicar, por ejemplo , las pruebas unitarias no deberían preocuparse por la secuencia de las pruebas individuales, suponiendo que las esté escribiendo correctamente), así que JUnit hace cumplir esto no garantizando cualquier secuencia de ejecución ... antes de Java 1.7 el orden de ejecución fue accidentalmente implícito por el orden de los métodos de prueba dentro de una clase, pero no era parte del contrato JUnit ... Algunas personas cambian a otros marcos de prueba para su integración pruebas, p. ej. TestNG, si encuentran que el foco de la unidad de prueba de JUnit está obstaculizando el desarrollo de sus pruebas)

El punto clave a tener en cuenta es que el ciclo de vida de Maven utiliza la fase de test para la ejecución de pruebas unitarias .

Cuando se trata de pruebas de integración , hay dos (y media) escuelas de pensamiento sobre la forma correcta de manejar las pruebas con Maven.

Escuela 1 - Failsafe e integration-test/verify

Esta escuela de pensamiento utiliza las fases posteriores al package para iniciar un contenedor, ejecutar las pruebas de integración, desmontar el contenedor y finalmente verificar los resultados de la prueba y fallar la compilación en caso de fallas en la prueba.

NUNCA EJECUTE mvn integration-test ya que eso no destruirá el contenedor correctamente, cada vez que crea que desea escribir mvn integration-test , realmente quiere escribir mvn verify (oh look, es más corto y más fácil de escribir también ... prima)

Entonces con esto haces lo siguiente:

Para obtener puntos extra brownie, usaría build-helper-maven-plugin:reserve-network-port vinculado a la fase de validate para garantizar que el servidor de prueba se inicie en un puerto de red no utilizado y luego use el filtrado de recursos contra los recursos de prueba para aprobar el puerto a través de las pruebas o el uso de una propiedad del sistema pasa a través de systemPropertyVariables para que el número de puerto esté disponible para las pruebas.

Ventajas

  • Clean Maven build
  • Si las pruebas fallan, no puede lanzar el proyecto
  • Puede mover las pruebas de integración a un perfil separado (por convención llamado run-its ) si las pruebas son demasiado lentas para ejecutar cada compilación.

Desventajas

  • Es difícil ejecutar las pruebas desde un IDE. Todas las pruebas de integración comienzan / finalizan en IT y aunque Maven sabe ejecutar pruebas que comienzan / finalizan en Test con Surefire y ejecutan pruebas que comienzan / finalizan en IT con Failsafe, es probable que su IDE no lo haga. Además, su IDE no va a iniciar el contenedor por usted, por lo que tiene que trabajar mucho a mano para ejecutar las pruebas de forma manual.
  • La depuración de las pruebas posiblemente requiera la conexión de dos depuradores, por ejemplo, uno para depurar la aplicación que se ejecuta en el contenedor y el otro para depurar los casos de prueba .

    mvnDebug -Dmaven.failsafe.debug=true verify

  • Combina tus pruebas con el proceso de construcción de Maven.

Escuela 2 - Módulo separado

Esta escuela de pensamiento mueve las pruebas de integración a un módulo separado que depende del módulo de war y copia la war en los recursos de prueba usando, por ejemplo, dependency:copy-dependencies ligadas a la fase de generate-test-resources junto con una dependencia de Tomcat7 para probar en contra.

Los casos de prueba se inician en el contenedor Tomcat7 utilizando el modo integrado

Ventajas

  • Las pruebas se pueden ejecutar en IDE
  • Las pruebas de integración están separadas de las pruebas unitarias, por lo que pedirle al IDE que ejecute todas las pruebas no iniciará las pruebas más lentas

Desventajas

  • El artefacto de war solo se reconstruye si pasa la fase del package , por lo tanto, debe ejecutar al menos mvn clean package periódicamente para actualizar el código bajo prueba cuando se utiliza el IDE.
  • El fracaso de las pruebas de integración no rompe la construcción del módulo de war , por lo que puede terminar liberando un artefacto de war roto y luego hacer que la construcción del reactor falle para el módulo de prueba de integración. Algunas personas contrarrestan este problema al tener el módulo de prueba de integración dentro de src/it y usar Maven Invoker Plugin para ejecutar las pruebas ... aunque eso proporciona una integración IDE más pobre, por lo que no recomiendo esa línea.
  • Es difícil obtener un informe de cobertura de prueba consolidado de Maven.
  • Tiene que codificar el inicio / detención del contenedor dentro de sus casos de prueba.

Escuela 2.5 - Fail safe con los casos de prueba iniciando su propio servidor Tomcat7

Este es un tipo de híbrido de los dos enfoques.

Utiliza Failsafe para ejecutar las pruebas, pero las pruebas en sí mismas son responsables de iniciar y detener el contenedor Tomcat7 en el que desea realizar la prueba.

Ventajas

  • No es necesario configurar el inicio / detención del servidor en Maven pom
  • IDE puede ejecutar todas las pruebas de forma segura (aunque las pruebas de integración pueden ser más lentas y es posible que no desee ejecutarlas, pero no todas fallarán a menos que exista una falla en la prueba)
  • Es más fácil depurar las pruebas de su IDE (solo hay un proceso para adjuntar, y el IDE generalmente facilita la depuración de las pruebas al proporcionar un corredor de prueba especial)

Desventajas

  • Tiene que codificar el inicio / detención del contenedor dentro de sus casos de prueba

Espero que lo anterior te ayude a entender las opciones que tienes. Puede haber otros ajustes pero, en general, lo anterior se considera la mejor práctica (es) para las pruebas de integración con Maven actualmente.