You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.
Describes how to take SeamTest coverage in a multi-module Maven project.
See also SeamTest coverage (maven+cobertura)
project project-ejb project-web project-ear project-common
Your tests are passing, but you get no coverage for the classes in the ejb project.
The Cobertura Maven Plugin instruments only the classes in the current sub-project ( in \target\generated-classes\cobertura) and uses those to take code coverage. By default instrumented classes from other sub-projects are not on the classpath, and you get no coverage for those.
To get coverage you need to put the instrumented classes from the relevant sub-projects (project-ejb in the above example) on the classpath for your SeamTests. Simply copying them over to project-web/target-classes doesn't work and getting the classpath right for JBoss embedded in Maven is already tricky. The easiest solution is to overwrite the project-ejb jar in your local maven repository with an instrumented one. After that you can execute your test as usual. The following section shows how to get the whole process automated.
We define a profile that instruments the ejb jar in place, aggregates the ejb module coverage with the SeamTests coverage (in the web module) and creates a report.
The cobertura maven plugin is not flexible enough to handle multiple projects, so we use the ant tasks via the AntRun plugin. Instrumenting the ejb jar in place might lead to packaging instrumented classes to your production ear, so we save the original file and restore it after the tests are done. (note that the script is not very smart: if your tests fail, you end up with an instrumented jar in your repository. You can make it smarter, but, hopefully, you wouldn't be deploying into production if tests are failing :))
Here's the profile we define:
<profile> <id>coverage</id> <build> <plugins> <plugin> <artifactId>maven-antrun-plugin</artifactId> <dependencies> <dependency> <groupId>net.sourceforge.cobertura</groupId> <artifactId>cobertura</artifactId> <version>1.9</version> </dependency> </dependencies> <executions> <execution> <phase>process-test-classes</phase> <id>instrument-ejb-jar</id> <configuration> <tasks> <taskdef classpathref="maven.runtime.classpath" resource="tasks.properties" /> <mkdir dir="${project.build.directory}/cobertura" /> <copy todir="${project.build.directory}/cobertura"> <fileset dir="../project-ejb/target/cobertura" /> </copy> <copy file="${settings.localRepository}/org/foobar/project-ejb/${project.version}/project-ejb-${project.version}.jar" tofile="${settings.localRepository}/org/foobar/project-ejb/${project.version}/project-ejb-${project.version}.jar.org" /> <cobertura-instrument> <includeClasses regex=".*" /> <excludeClasses regex=".*\DontLikeInstrumentation.*" /> <instrumentationClasspath> <pathelement location="${settings.localRepository}/org/foobar/project-ejb/${project.version}/project-ejb-${project.version}.jar" /> </instrumentationClasspath> <!-- or use this:--> <!-- <fileset dir="${settings.localRepository}/org/foobar/project-ejb/${project.version}"> <include name="project-ejb-${project.version}.jar" /> </fileset> --> </cobertura-instrument> </tasks> </configuration> <goals> <goal>run</goal> </goals> </execution> <execution> <phase>integration-test</phase> <id>cobertura-report</id> <configuration> <tasks> <taskdef classpathref="maven.runtime.classpath" resource="tasks.properties" /> <mkdir dir="${project.build.directory}/site/cobertura" /> <cobertura-report format="html" datafile="${project.build.directory}/cobertura/cobertura.ser" destdir="${project.build.directory}/site/cobertura"> <fileset dir="${basedir}/src/main/java"> <include name="**/*.java" /> </fileset> <fileset dir="../project-ejb/src/main/java"> <include name="**/*.java" /> </fileset> </cobertura-report> <copy overwrite="true" file="${settings.localRepository}/org/foobar/project-ejb/${project.version}/project-ejb-${project.version}.jar.org" tofile="${settings.localRepository}/org/foobar/project-ejb/${project.version}/project-ejb-${project.version}.jar" /> </tasks> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile>
And here's how to use it:
I've been tackling thins again and I decied to take Juan Pablo's suggestion and redo this using the jar and install Maven plugins. Here's what I came up with.
In project-ejb and project-common define the following profile:
<profiles> <profile> <id>coverage</id> <dependencies> <dependency> <groupId>net.sourceforge.cobertura</groupId> <artifactId>cobertura</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>cobertura-maven-plugin</artifactId> <executions> <execution> <id>cobertura-instrument</id> <phase>pre-integration-test</phase> <goals> <goal>instrument</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <executions> <execution> <id>cobertura-jar</id> <phase>post-integration-test</phase> <goals> <goal>jar</goal> </goals> <configuration> <classifier>cobertura</classifier> <classesDirectory>${basedir}/target/generated-classes/cobertura</classesDirectory> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-install-plugin</artifactId> <executions> <execution> <id>cobertura-install</id> <phase>install</phase> <goals> <goal>install</goal> </goals> <configuration> <classifier>cobertura</classifier> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles>
What this does is instrumend your classes, jar them and install them in your local repository with the 'cobertura' classifier. By using a classifier for you instrumented classes, you can be sure that no instrumented classes end up in a production build.
In your project-web define the following profile:
<profile> <id>coverage</id> <dependencies> <dependency> <groupId>net.sourceforge.cobertura</groupId> <artifactId>cobertura</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.foobar</groupId> <artifactId>project-ejb</artifactId> <version>1.0-SNAPSHOT</version> <classifier>cobertura</classifier> </dependency> <dependency> <groupId>org.foobar</groupId> <artifactId>project-comon</artifactId> <version>1.0-SNAPSHOT</version> <classifier>cobertura</classifier> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-antrun-plugin</artifactId> <dependencies> <dependency> <groupId>net.sourceforge.cobertura</groupId> <artifactId>cobertura</artifactId> <version>1.9</version> </dependency> </dependencies> <executions> <execution> <id>merge-cobertura-datafiles</id> <phase>process-test-classes</phase> <configuration> <tasks> <taskdef classpathref="maven.runtime.classpath" resource="tasks.properties" /> <cobertura-merge datafile="${project.build.directory}/cobertura/cobertura.ser"> <fileset dir="../"> <include name="project-ejb/target/cobertura/cobertura.ser" /> <include name="project-common/target/cobertura/cobertura.ser" /> </fileset> </cobertura-merge> </tasks> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile>
This makes your build dependent on the instrumented classes (with 'cobertura' classifier) and merges the coverage data from the project-ejb and project-common modules. Unfortunately, the Maven cobertura plugin has no 'merge' goal, so we have to resort to Ant to do the merging.
How to use it:
Notes
Apperantly, JBoss embedded doesn't like instrumented MDB's, so you may want to exclude those. Otherwise you may get the following error:
Caused by: java.lang.RuntimeException: Unable to choose messagingType i for MDB TerminalStateChangedListener from [interface javax.jms.MessageL interface net.sourceforge.cobertura.coveragedata.HasBeenInstrumented]