Situación inicial: supongamos la siguiente estructura de proyecto

./project
|-pom.xml
|-project-api
| |- pom.xml
|-project-impl-1
| |- pom.xml
|-project-tests
| |- pom.xml
  • En este proyecto los tests correspondientes a project-api se encuentran en el módulo project-tests, lo cuál está considerado como una buena práctica. Este módulo únicamente contiene los tests, es decir, las carpetas ./src/main/java, ./src/main/resources, etc. están vacías.
  • El plugin de Cobertura se encuentra configurado correctamente.

El problema: los tests de project-tests se ejecutan correctamente, si bien no se está obteniendo la cobertura de los mismos, el plugin de Cobertura solamente es capaz de dar la cobertura del código dentro de un mismo módulo.

Análisis: Cobertura sólo instrumenta las clases dentro de un mismo módulo, dejándolas en el directorio ./target/generated-classes/cobertura, para luego usarlas al calcular la cobertura del código. Buscando la manera de solucionar todo esto, la única referencia la he encontrado en la documentación de Seam, el framework open source de la gente de Hibernate y compañía (de hecho este post ha sido fusiladotiene exactamente la misma estructura que la página referenciada).

La solución que se propone en el enlace anterior pasa por incrustar un script de Ant que copia las clases instrumentadas de un módulo a otro, ejecuta el plugin de Cobertura y deja los resultados en el proyecto inicial. La solución que se va a exponer deja los resultados del test de cobertura en el proyecto correspondiente a los tests (lo cual me parece más correcto), es más concisa y más a la Maven way.

Solución: el plugin de Cobertura se ejecuta al lanzar el site del proyecto, por lo que vamos a aprovechar para montar un jar con las clases instrumentadas y subirlo a nuestro repositorio local (es decir, ejecutar un install y no un deploy, ya que no nos interesará que este nuevo .jar esté en nuestro repositorio público). Enlazaremos la ejecución de los plugins a la fase de site, que es cuándo se generan las clases instrumentadas de Cobertura.

Así pues, en el pom.xml del módulo project-impl-1 incluimos las siguientes entradas:

[...]
<build>
[...]
<plugins>
[...]
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution><!-- jar con las clases instrumentadas por cobertura -->
<id>cobertura-jar</id>
<phase>site</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>cobertura</classifier>
<classesDirectory>${basedir}/target/generated-classes/cobertura</classesDirectory>
</configuration>
</execution>
</executions>
</plugin>

<plugin><!-- instalamos el jar en el repositorio local -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<executions>
<execution>
<id>cobertura-install</id>
<phase>site</phase>
<goals>
<goal>install</goal>
</goals>
<configuration>
<classifier>cobertura</classifier>
</configuration>
</execution>
</executions>
</plugin>
[...]
</plugins>
[...]
</build>
[...]

La clave está en el elemento classifier, que nos permite generar el jar que queremos añadiéndole el sufijo que le indicamos, lo cual nos permite generar varios .jars distintos dentro de un mismo proyecto Maven 2.

En el módulo de tests, configuramos el plugin de Cobertura para que utilice el .jar con las clases instrumentadas (esto es, lo añadimos como dependencia al plugin) y sobreescribimos el elemento sourceDirectory. Este último paso es necesario debido a que Cobertura necesita tener acceso a los fuentes para generar el informe de cobertura del código. En fin, que en el pom.xml correspondiente a project-tests incluimos las siguientes entradas:

<build>
<sourceDirectory>${basedir}/../project-impl-1/src/main/java</sourceDirectory>

<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<dependencies>
<dependency><!-- cobertura necesita tener las clases instrumentadas en el classpath -->
<groupId>atlas.dpugd</groupId>
<artifactId>project-impl-1</artifactId>
<version>1.0.0</version><!-- se sobreentiende que esta versión es la generada en el pom de <tt>project-impl-1</tt> -->
<classifier>cobertura</classifier>
</dependency>
</dependencies>
</plugin>
</plugins>

</build>

et le vôila, ya hemos conseguido la cobertura de los tests dentro de un proyecto multi-módulo de Maven 2 y lo más importante, integrándolo de un modo transparente dentro del proceso de generación de la documentación, sin tener que efectuar ningún paso intermedio adicional.