Maven, Jenkins, Sonar y tests de integracion
0. Índice de contenidos.
- 1. Introducción
- 2. Entorno
- 3. Configuración básica de Maven
- 4. Conseguir que las builds de Jenkins no fallen
- 5. Tener las métricas en Sonar
- 6. Conclusiones
1. Introducción
En otros tutoriales ya hemos hablando varias veces de cómo hacer tests unitarios e incluso cómo podemos hacer tests de integración levantando el contexto de Spring o un contexto JEE con Arquilian. Estos tests sin dejar de ser tests de integración, porque dependen de su éxito no sólo de la correcta implementación de la pieza que estoy probando, tienen la ventaja de que todo el contexto auxiliar del que dependen lo podemos proporcionar dentro de nuestros proyecto y seguimos teniendo el control del mismo; por lo que se ejecutan y suman sus métricas como si fueran tests unitarios.
Sin embargo no siempre es posible proporcionar estos «mini-contextos» y nuestras aplicaciones en muchos casos no corren aisladas, en muchos casos hay que conectarse a muchos otros servidores con distintos protocolos, HTTP, FTP, SSH, Samba, etc. En estos casos es en los que nos vamos a centrar.
Queremos hacer tests de integración que sumen en las métricas de cobertura y de tests para saber cuanto código tengo probado y llevar un control del total de tests ejecutados, exitos, fallos e ignorados.
Dadas estos objetivos, damos por sentado que ya tenemos montado nuestro entorno de integración contínua con Maven, Jenkins y Sonar; así que sumamos a nuestra lista de desables que todo quede integrado de una manera ejecutiva.
En este tutorial contamos el añadido de configuración necesario para tener estos tests de integración añadidos en nuestras métricas y bajo control, sin entrar a contar cómo se monta todo un entorno de integración contínua que queda fuera del alcance propio del tutorial.
2. Entorno
Este tutorial está escrito usando el siguiente entorno:
- Hardware: Portátil MacBook Pro Retina 15′ (2,3 GHz Intel Core i7, 16GB DDR3 SDRAM).
- Sistema Operativo: Mac OS X Lion 10.9.2
- Apache Maven 3.0.4
- Jenkins 1.554
- Sonar 3.7.4
3. Configuración básica de Maven
Este tipo de tests podríamos ejecutarlos como el resto de tests unitarios, pero entonces todo el entorno del que dependen debería estar disponible en cualquier sitio donde ejecutase los tests, y recordemos que estamos hablando de tests de integración y no de tests unitarios. Incluso podría darse el caso de que incluso en el entorno de integración fallasen los tests debido a la inestabilidad de estos sistemas externos; en tal caso puede que no nos interesa que se aborten las «builds» aunque si que se deberían generar alertas, y si estos test se ejecutan en la fase de «test» de Maven junto al resto, cuando fallan se aborta la ejecución.
Otro motivo, yo diría que aún más importante para que no se aborte la ejecución en caso de fallo, es que puede que nos interese cerrar/limpiar/liberar un contexto, que se necesite para la ejecución del test, haya o no fallado el test.
Por suerte Maven ya tiene previsto estas situaciones y tiene definido en su ciclo de vida las fases «pre-integration-test», «integration-test» y «post-integration-test». Para poder beneficiarnos de esta característica de Maven sólo tenemos que hacer uso del plugin de Maven Failsafe que con la configuración básica y cumpliendo con la convención de llamar a nuestros tests de integración con el sufijo «IT» ya tendríamos el mínimo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
... <build> <plugins> .... <plugin> <artifactId>maven-failsafe-plugin</artifactId> <version>2.14.1</version> <dependencies> <dependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit47</artifactId> <version>2.14.1</version> </dependency> </dependencies> <configuration> <testFailureIgnore>true</testFailureIgnore> </configuration> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> </plugin> </plugins> </build> ... |
Nota: Según la convención también podríamos llamar a estos tests con el sufijo «IntegrationTest» pero al terminar en «Test» también se ejecutarían en la fase de «Test» y no nos interesa.
4. Conseguir que las builds de Jenkins no fallen
Por suerte, Jenkins y Maven se integran perfectamente y con la configuración del Failsafe plugin indicando «testfailureignore» a «true» Jenkins ya lo tiene en cuenta y si los tests que se ejecutan en la fase de «integration-tests» fallan se continúa con la «build» y no se marca como fallo. En caso de fallar algún test de integración la «build» se marca como inestable y se enviarán notificaciones si así está configurado.
Así que en lo que respecta a Jenkins no tenemos que tocar ninguna configuración adicional, y se seguirá ejecutando tal y como hasta ahora.
5. Tener las métricas en Sonar
Ahora que ya ejecutamos nuestros tests de integración, y lo hacemos en un entorno de integración continua, nos interesa explotar sus métricas junto son el resto de métricas que ya nos proporciona Sonar. En primer lugar es configurar Sonar para que nos muestre estas métricas
Para hacer esto tenemos que tocar en la configuración de los Widgets de Sonar en un par de sitios. Primero configuramos en el «dashboard» que aparezca la columna «Overall Coverage», el valor de esta columna nos va a mostrar el porcentaje global de cobertura sumando el código cubierto tanto en la ejecución de tests unitarios como el de tests de integración. Por otro lado, configuramos el «dashboard» de los proyectos añadiendo el widget «Integration Tests Coverage» que nos va a mostrar 2 medidas, la cobertura específica de los tests de integración mas la cobertura global.
Una vez que ya tenemos preparado Sonar, nos falta que Jenkins al ejecutar Maven de nuestro proyecto nos envíe estas métricas. Para ello hay que configurar el plugin de cobertura de JaCoCo, el mismo que utiliza Sonar por defecto, y enlazar el plugin de FailSafe con el de JaCoCo para medir la cobertura de los tets de integración.
Otro problema que tenemos al ver las métricas en Sonar es que no hay ninún plugin de Sonar que nos muestre el número de tests de integración o tests globales. Así que aquí lo que vamos a hacer en una solución a modo de «workaround» que consiste en sumar el número y resultado de tests de integración al de tests unitarios, de forma que el Widget de «Unit Tests Coverage» que muestra Sonar va a seguir mostrando la cobertura propia de los tests unitarios, pero en la sección de resumen, «Unit test success», no sólo mostrará los tests unitarios, también incluye la suma de los tests de integración.
Para configurar esto lo haremos en nuestro POM dejando finalmente la configuración de los plugins de JaCoCo y Failsafe como sigue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
... <properties> <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin> <sonar.jacoco.itReportPath>${project.basedir}/target/jacoco-it.exec</sonar.jacoco.itReportPath> </properties> ... <build> <plugins> ... <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.6.5.201403032054</version> <configuration> <propertyName>jacoco.agent.argLine</propertyName> <destFile>${sonar.jacoco.itReportPath}</destFile> <append>true</append> </configuration> <executions> <execution> <id>agent</id> <goals> <goal>prepare-agent</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-failsafe-plugin</artifactId> <version>2.14.1</version> <dependencies> <dependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit47</artifactId> <version>2.14.1</version> </dependency> </dependencies> <configuration> <argLine>${jacoco.agent.argLine}</argLine> <testFailureIgnore>true</testFailureIgnore> <reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory> </configuration> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> </plugin> </plugins> </build> |
6. Conclusiones
Hemos visto como conseguir tener controlados nuetsros tests de integración en un entorno de integración contínua sin que se conviertan en bloqueantes en caso de que los sitemas de terceros de los que dependen no estén disponibles y provoquen que fallen. Aunque sin perder en ningún momento las alertas ni las métricas de cobertura y éxitos de todos nuestros tests.
Es cierto que la visualización del número de tests no se puede ir al grano fino y distinguir cuántos son unitarios y cuantos de integración, pero desde el punto de vista ejecutivo seguramente sea más interesante tener el resumen con la suma de ambos, y a falta de disponer del grano fino, mejor esta solución que ninguna.
Espero que a alguno de vosotros os pueda servir de ayuda y os ahorre algo de trabajo dado el caso.