The problem is simple:
After writing a bunch of JUnit tests for the serverside part of a J2EE Application (and reaching a sufficient code coderage), one would want the same for the WebApp.
My solution, shortly put:
- Instrument the JAR/WAR/EAR file with coverage information
- Deploy the instrumented application
- Run the (hopefully automated) end-to-end tests
Luckily, EMMA (which is the code coverage tool of my choice) supports analysis inside the AppServer.
So this is how I did it:
Instrument the application:
This is done in my Ant buildscript using theemma instr
task. Since EMMA cannot instrument WAR files directly, the first instrumentation step must be performed in the WebApp's buildscript right before packaging the WAR file:
<emma>
<instr mode="overwrite" metadatafile="${dir.coverage}/coverage.em" merge="false">
<instrpath>
<pathelement location="${dir.client.build}/WEB-INF/classes"/>
</instrpath>
</instr>
</emma>Then, before packaging the EAR file, I instrument the other modules (which in my case all start with "wb") and merge the coverage metadata:
<emma>
<instr mode="overwrite" metadatafile="${dir.coverage}/coverage.em" merge="true">
<instrpath>
<fileset dir="${build.dir}" includes="**/wb*.jar"/>
</instrpath>
</instr>
</emma>
When deploying the EAR file to the AppServer, make sure theemma.jar
is in the AppServer's startup classpath
Now, anytime you want to make a snapshot of the current code coverage, you can use the
emma ctl
Ant task.
Since I use a two-node cluster, I must fetch the coverage data from each node:
<emma>
<ctl connect="node1:47653">
<!-- dump coverage data, no merge, leaving dump-on-exit enabled: -->
<command name="coverage.get" args="${dir.coverage}/coverage.ec, false, false"/>
</ctl>
<ctl connect="node1:47653">
<!-- dump coverage data, merge with server1, leaving dump-on-exit enabled: -->
<command name="coverage.get" args="${dir.coverage}/coverage.ec, true, false"/>
</ctl>
<report>
<sourcepath>
<!-- the source paths of all intrumented classes go here...-->
</sourcepath>
<fileset dir="${dir.coverage}">
<include name="coverage.ec"/>
<include name="coverage.em"/>
</fileset>
<html outfile="${dir.coverage}/coverage.html"/>
</report>
</emma>A few notes:
- If the server is restarted, the coverage data will get lost. To avoid this, leave "dump-on-exit" (the third
coverage.get
parameter) enabled and include the dumped serverside "coverage.ec" files in the report. - When redeploying the application, you must reset the coverage data (using the
coverage.reset
command) and delete the "coverage.ec" file from the server. - To reduce serverside memory usage, you may reset the coverage data after each
coverage.get
. In this case, you must always use "merge" mode when fetching new coverage data (the secondcoverage.get
parameter)
- If the server is restarted, the coverage data will get lost. To avoid this, leave "dump-on-exit" (the third