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:

  1. Instrument the JAR/WAR/EAR file with coverage information
  2. Deploy the instrumented application
  3. 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:

  1. Instrument the application:
    This is done in my Ant buildscript using the emma 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>



  2. When deploying the EAR file to the AppServer, make sure the emma.jar is in the AppServer's startup classpath



  3. 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 second coverage.get parameter)