EMMA User Guide

A Step-by-Step Introduction to EMMA coverage toolkit


Table of Contents

1. Overview
2. Getting Started (command line)
2.1. Adding EMMA command line tools to your classpath
2.2. emmarun: instrumenting Java classes on-the-fly
2.3. Offline mode: separating instrumentation and execution
3. Getting Started (ANT)
3.1. Adding EMMA tasks to your ANT build
3.2. <emmajava>: instrumenting Java classes on-the-fly
3.3. Offline mode: separating instrumentation and execution

1. Overview

EMMA is a tool for measuring coverage of Java software. Such a tool is essential for detecting dead code and verifying which parts of your application are actually exercised by your test suite and interactive use.

EMMA's design strives for several, very elusive in their combination, goals:

  • report rich coverage analysis data without introducing significant overhead during either build or execution time

  • be useful in team development environments, while at the same time enabling fast individual develop-test cycle

  • support quick development and testing of small standalone Java applications as well as scale up to massive enterprise sotfware suites containing thousands of Java classes

EMMA differs from other coverage tools in its extreme orientation towards fast iterative develop-test style of writing software. JVM Profiler Interface (JVMPI)-based tools do not require an instrumented source build, but the runtime overhead of running with JVMPI on is empirically known to be very high and results in depressingly slow testsuite runs. For tools based on source code instrumentation, having to wait for a full source code rebuild just to check coverage metrics is not something a normal developer wants to do several times during a day. EMMA's goal is to be so unintrusive that frequent daily checking of coverage numbers becomes second nature to every developer on the team, if not a completely automatic byproduct of every test run.

2. Getting Started (command line)

This section introduces EMMA command line tools. It starts with an example of how to run an application so that coverage instrumentation is performed on-the-fly, as the classes are loaded by the JVM, and then repeats the same process by breaking it into distinct instrumentation/execution/reporting steps.

Sample source code

The source code located in examples/src directory of EMMA distribution is used for all examples in this tutorial.

Section 3, “Getting Started (ANT)” works with the same sample application through Apache ANT build tool. All of EMMA's command-line functionality is available via EMMA's ANT tasks and there is some duplication of content between this and the following sections, so you might want to skip ahead if you expect to obtain coverage through ANT builds exclusively. You should also skip ahead if you've already gone through "Getting Started" steps on EMMA's web site.

2.1. Adding EMMA command line tools to your classpath

The recommended way to install EMMA command.line tools is to make emma.jar an extension library for your Java Runtime Environment (JRE). This is accomplished simply by copying emma.jar to <your jre dir>/lib/ext/ directory for whichever JRE you use from command line.

EMMA distribution neither depends on any external Java libraries nor includes them inside EMMA jars. This means installing EMMA as a JRE extension will not pollute your classpath with unknown versions of Java libraries that you might be using elsewhere in your work. This also has the advantage of setting up emma.jar as a trusted Java library, which is useful for collecting coverage in security sensitive configurations.

Still, if you are wary of adding a third-party library as a standard JRE extension, just make sure that all your EMMA command line invocations add emma.jar to the JVM classpath:

>java -cp .../lib/emma.jar <emma or emmarun command>

2.2. emmarun: instrumenting Java classes on-the-fly

Assuming you are in the examples directory of EMMA distribution, start by compiling the example source code:

>mkdir out 
>javac -d out -g src/*.java src/search/*.java

You can now run the main demo driver:

>java -cp out Main
main(): running doSearch()...
main(): done

To run the same program with coverage data collection, just insert emmarun in front of your program's main class name:

>java emmarun -cp out Main
main(): running doSearch()...
main(): done
EMMA: writing [txt] report to [...coverage.txt] ...

The default text coverage report is generated in the current directory:

[EMMA v2.0.3611 report, generated Sun Jan 11 14:18:08 CST 2004]
-------------------------------------------------------------------------------
OVERALL COVERAGE SUMMARY:
[class, %]      [method, %]     [block, %]      [line, %]       [name]
100% (3/3)      100% (7/7)      95%  (116/122)  100% (29/29)    all classes

OVERALL STATS SUMMARY:

total packages: 2
total classes:  3
total methods:  7
total executable files: 3
total executable lines: 29

COVERAGE BREAKDOWN BY PACKAGE:

[class, %]      [method, %]     [block, %]      [line, %]       [name]
100% (2/2)      100% (4/4)      91%  (64/70)    100% (18/18)    search
100% (1/1)      100% (3/3)      100% (52/52)    100% (11/11)    default package
-------------------------------------------------------------------------------

Code coverage has never been easier! This on-the-fly instrumentation mode is handy for light-weight testing of main() test methods, individual classes, and small- to- mid-size programs. emmarun also works well with Swing applications.

Other report types

By default, emmarun generates a plain-text report only. The default report's depth is all which means to show the overall coverage summary followed by breakdown by package. You can increase the default depth to include package and source file summaries. This and many other aspects of EMMA report generation can be configured using command line (-D<report property>=<value>) or an EMMA configuration file. See Chapter3, EMMA Property Reference in the reference manual for full details on EMMA configuration. Also, all EMMA command line tools provide usage information in response to -h option.

emmarun application runner uses an instrumenting classloader to add bytecode instrumentation to Java classes as they are being loaded by the JVM. For efficiency reasons, emmarun does not scan your entire classpath before it starts running. This has the side effect of only reporting on the classes that got loaded by the application. If your intent is to base coverage metrics on the full set of classes in the classpath, you can use the -f option.

Although it was not the case with this tutorial's sample code, chances are your application has third-party library dependencies and you are not interested in their coverage metrics. There are two ways to handle this:

  • List third-party libraries in the JVM's classpath, not emmarun's -cp option:

    >java -cp ...somelib.jar emmarun -cp out Main
  • Use a coverage filter to make sure that only the classes of interest are instrumented:

    >java emmarun -cp out;...somelib.jar -ix +Main,+search.*  Main
If these techniques are not sufficient (e.g., you need to exclude testcases from coverage and they are in the same Java packages as the application code and do not follow a sensible naming pattern), you can always switch to offline instrumentation as described next.

Further reading. This has been a quick intro to EMMA's on-the-fly command line instrumentation mode. For further details see Section2, <emmajava>/emmarun in the reference manual.

2.3. Offline mode: separating instrumentation and execution

As convenient as the on-the-fly mode is, in many cases it is not sufficient. For example, running a commercial J2EE container in a custom instrumenting classloader is practically impossible. Certain (bad) coding practices also fail for code executing in a custom classloader. Finally, in large scale development there is a common need to collect and merge coverage data from multiple execution runs and multiple JVM processes.

This is where separate instrument/execute/report phases are a necessity. This section repeats the previous exercise using emma command line tool, which provides several subcommands for managing EMMA's offline code coverage analysis: instr, merge, and report (there is also a run equivalent of emmarun for scripting convenience).

If you skipped the previous exercise, you need to compile the sample source code at this time:

>cd ...samples
>mkdir out 
>javac -d out -g src/*.java src/search/*.java

Now, you are going to instrument classes produced by javac (it's kind of a second compilation phase). EMMA can do "in place" instrumentation (overwrite mode), whereby the classes and jar files are overwritten with their instrumented versions. However, this is easy to abuse, so for now we are going to be careful and create a separate directory for coverage-instrumented output:

>mkdir outinstr
>java emma instr -d outinstr -ip out

EMMA: processing instrumentation path ...
EMMA: instrumentation path processed in 116 ms
EMMA: [3 class(es) instrumented, 0 resource(s) copied]
EMMA: metadata merged into [...coverage.em] {in 31 ms}

Several instrumented classes have been added to outinstr directory and class metadata has been dumped into a coverage.em file. Note that instr accepts a regular classpath string (containing archives and class directories) as input: this is very convenient for makefile integration because existing makefiles tend to already have macros for various classpaths in a project.

Instrumenting just the right classes

Unlike some other tools, EMMA's design is based around filtering for the right set of classes at instrumentation time. Doing so allows EMMA to scale to enterprise size projects and ensures the best performance throughout all three offline stages: instrumentation, execution, and reporting. To select a subset of classes to be processed, you could give instr several -ix options, each containing a comma-separated list of inclusion/exlusion patterns. See Section6.2, Coverage filters in the reference manual for full details.

Now the instrumented application can be run. In a real-world project you might be packaging the instrumented classes in an archive to be deployed in an application server, but in this tutorial we just load the classes from disk:

>java -cp 1outinstr;out Main

EMMA: collecting runtime coverage data ...
main(): running doSearch()...
main(): done
EMMA: runtime coverage data merged into [...coverage.ec] {in 32 ms}

When the JVM exits, EMMA runtime dumps the runtime coverage profile into a coverage.ec file (the precise names and locations of all files created by EMMA are configurable, the above is just EMMA's default behavior).

Don't forget the classpath

1

Notice an important detail: the instrumented classes must appear first in the classpath. Also, instr does not copy non-executable items like interfaces and resource bundles, so you need to have the original out behind outinstr for everything to work.

And finally, we combine the class metadata and runtime coverage profile to produce a plain text and an HTML reports:

>java emma report -r txt,html -in coverage.em -in coverage.ec

EMMA: 2 file(s) read and merged in 43 ms
EMMA: writing [txt] report to [...coverage.txt] ...
EMMA: writing [html] report to [...coverage/index.html] ...

Note that there could be several instrumentation and execution stages and report will happily merge all of the results in memory before generating the reports. To merge all files on disk (for maintenance and disk storage reasons) you can use merge:

>java emma merge -in coverage.em -in coverage.ec -out coverage.es

EMMA: processing input files ...
EMMA: 2 file(s) read and merged in 42 ms
EMMA: merged/compacted data written to [...coverage.es] {in 58 ms}

In EMMA's offline mode, you are in complete control of mixing and matching metadata and coverage data from different application runs. You can instruct all tools to merge all types of data in the same file or keep everything in separate file repositories. EMMA tools default to merge=true output file mode for metadata and runtime coverage data, but properties exist to alter this behavior. See Chapter3, EMMA Property Reference in the reference manual for further details.

Further reading. This has been a quick intro to EMMA's offline instrumentation tools for command line. For further details read the reference manual starting with Section3, <instr>/instr.

3. Getting Started (ANT)

This section introduces EMMA ANT tasks. It starts with an example of how to run an application from ANT so that coverage instrumentation is performed on-the-fly, as the classes are loaded by the JVM, and then repeats the same process by breaking it into distinct instrumentation/execution/reporting steps. The ANT logic sequence will be equivalent to what was described previously, in Section 2, “Getting Started (command line)”. Additionally, the ANT build.xml files created below will have logic for enabling and disabling coverage through ANT command line.

Sample source code and ANT build files

The source code located in examples/src directory of EMMA distribution is used for all examples in this tutorial. EMMA distribution also includes two sample ANT buildfiles, build-onthefly.xml and build-offline.xml, that correspond to the two approaches to collecting coverage. Although it would have been possible to keep everything in a single file, using distinct files allows for more clarity.

3.1. Adding EMMA tasks to your ANT build

EMMA ANT tasks can be deployed in any of the many ways available for custom ANT taskdefs. This tutorial assumes that you have an EMMA distribution directory that contains both emma.jar and emma_ant.jar. The latter archive is what contains EMMA taskdefs, however, both archives need to be visible to ANT. The easiest way to accomplish this is with the following definitions in your build.xml:

  <!-- directory that contains emma.jar and emma_ant.jar: -->
  <property name="emma.dir" value="${basedir}/../lib" />

  <path id="emma.lib" >1
    <pathelement location="${emma.dir}/emma.jar" />
    <pathelement location="${emma.dir}/emma_ant.jar" />
  </path>

  <taskdef resource="emma_ant.properties" classpathref="emma.lib" />

1

Even though this path definition can be merged into the <taskdef>, a path element with this id will come in handy later in the build.

3.2. <emmajava>: instrumenting Java classes on-the-fly

Let's create a simple ANT build file for the source code in examples/src. Add this after EMMA task definitions:

  <!-- root directory for the example source code: --> 
  <property name="src.dir" value="${basedir}/src" />

  <!-- javac class output directory: -->
  <property name="out.dir" value="${basedir}/out" />

  <target name="init" >
    <mkdir dir="${out.dir}" />
    <path id="run.classpath" >
      <pathelement location="${out.dir}" />
    </path>
  </target>

  <target name="compile" depends="init" description="compiles the example source code" >
    <javac debug="on" srcdir="${src.dir}" destdir="${out.dir}" />
  </target>

  <target name="run" depends="init, compile" description="runs the examples" >
    <java classname="Main"
          classpathref="run.classpath"
    >
    </java>
  </target>

You can now compile and run the example:

>ant run
Buildfile: build.xml

init:
    [mkdir] Created dir: .../examples/out

compile:
    [javac] Compiling 4 source files to .../examples/out

run:
     [java] main(): running doSearch()...
     [java] main(): done

BUILD SUCCESSFUL
Total time: 5 seconds

<emmajava> is an EMMA extension of ANT stock <java> task that is an ANT adapter to the same instrumenting application runner as used by EMMA emmarun command line tool. Upgrading your build to do code coverage on-the-fly is very easy: just replace <java> tags with <emmajava> tags for tasks that run your application or test cases. Don't worry, your build is not now in a permanent coverage-enabled mode: <emmajava> becomes a pass-through to the normal <java> when its enabled attribute is set to false:

  <target name="emma" description="turns on EMMA's on-the-fly instrumentation mode" >
    <property name="emma.enabled" value="true" />
  </target>

  <target name="run" depends="init, compile" description="runs the examples" >
    <emmajava enabled="${emma.enabled}" libclasspathref="emma.lib" 
              classname="Main"
              classpathref="run.classpath"
    >
    </emmajava>
  </target>

Now, whenever you insert emma before any run targets on ANT's command line, you enable on-the-fly coverage instrumentation and reporting (but ANT commands without emma continue to function as before):

>ant emma run
Buildfile: build.xml

emma:

init:
    [mkdir] Created dir: .../examples/out

compile:
    [javac] Compiling 4 source files to .../examples/out

run:
 [emmajava] main(): running doSearch()...
 [emmajava] main(): done
 [emmajava] EMMA: writing [txt] report to [.../coverage.txt] ...

BUILD SUCCESSFUL
Total time: 7 seconds

The default text coverage report is generated in the current directory:

[EMMA v2.0.3611 report, generated Sun Jan 11 14:18:08 CST 2004]
-------------------------------------------------------------------------------
OVERALL COVERAGE SUMMARY:

[class, %]      [method, %]     [block, %]      [line, %]       [name]
100% (3/3)      100% (7/7)      95%  (116/122)  100% (29/29)    all classes

OVERALL STATS SUMMARY:

total packages: 2
total classes:  3
total methods:  7
total executable files: 3
total executable lines: 29

COVERAGE BREAKDOWN BY PACKAGE:

[class, %]      [method, %]     [block, %]      [line, %]       [name]
100% (2/2)      100% (4/4)      91%  (64/70)    100% (18/18)    search
100% (1/1)      100% (3/3)      100% (52/52)    100% (11/11)    default package
-------------------------------------------------------------------------------

Other report types

By default, <emmajava> generates a plain-text report only. The default report's depth is all which means to show the overall coverage summary followed by breakdown by package. You can increase the default depth to include package and source file summaries. This and many other aspects of EMMA report generation can be configured using various attributes and nested elements that <emmajava> adds to <java>. These extensions only take effect when the task is in enabled state and have no impact on the build otherwise. See Chapter3, EMMA Property Reference in the reference manual for full details on EMMA configuration.

<emmajava> application runner uses an instrumenting classloader to add bytecode instrumentation to Java classes as they are being loaded by the JVM. For efficiency reasons, <emmajava> does not scan your entire classpath before it starts running. This has the side effect of only reporting on the classes that got loaded by the application. If your intent is to base coverage metrics on the full set of classes in the classpath, you can set fullmetadata task attribute to true. Here is an example that also adds some extra reports and makes sure the HTML report generator has access to the source code by setting sourcepath="${src.dir}":

  <!-- output directory used for EMMA coverage reports: -->
  <property name="coverage.dir" value="${basedir}/coverage" />

  <target name="run" depends="init, compile" description="runs the examples" >
    <emmajava enabled="${emma.enabled}" libclasspathref="emma.lib" 
              fullmetadata="yes" sourcepath="${src.dir}"
              classname="Main"
              classpathref="run.classpath"
    >
      <txt outfile="${coverage.dir}/coverage.txt" />
      <xml outfile="${coverage.dir}/coverage.xml" />
      <html outfile="${coverage.dir}/coverage.html"  />
    </emmajava>
  </target>

Although this was not the case with this tutorial's sample code, chances are your application has third-party library dependencies and you are not interested in their coverage metrics. There are two ways to handle this with <emmajava>:

1

List libraries in the JVM's classpath, not <emmajava>'s classpath. You do that by adding them to <emmajava>'s emmaclasspath attribute instead of the usual classpath:

    <emmajava enabled="${emma.enabled}" libclasspathref="allmylibs.path"1 
              classname="Main"
              classpathref="run.classpath"
    >
    </emmajava>

1

Use a coverage filter to make sure that only the classes of interest are instrumented:

    <emmajava enabled="${emma.enabled}" libclasspathref="emma.lib" 
              classname="Main"
              classpathref="run.classpath"
    >
      1<filter includes="Main, search.*" />
    </emmajava>

If these techniques are not sufficient (e.g., you need to exclude testcases from coverage and they are in the same Java packages as the application code and do not follow a sensible naming pattern), you can always switch to offline instrumentation as described next. Offline instrumentation does not keep everything in memory and ultimately gives you much more control over what gets instrumented.

To summarize, an existing build.xml can be converted to use EMMA's on-the-fly instrumentation mode by following these steps:

  1. add EMMA task definitions

  2. replace the necessary invocations of <java> with <emmajava>

  3. configure coverage paths and inclusion/exclusion filters

  4. configure coverage reports

  5. make sure there is a way to turn coverage instrumentation off

Futher reading. This has been a quick intro to EMMA's on-the-fly ANT instrumentation mode. For further details see Section2, <emmajava>/emmarun in the reference manual.

3.3. Offline mode: separating instrumentation and execution

As convenient as the on-the-fly mode is, in many cases it is not sufficient. For example, running a commercial J2EE container in a custom instrumenting classloader is practically impossible. Certain (bad) coding practices also fail for code executing in a custom classloader. Finally, in large scale development there is a common need to collect and merge coverage data from multiple execution runs and multiple JVM processes.

This is where separate instrument/execute/report phases are a necessity. This section repeats the previous exercise using <emma> ANT task, which provides several subtasks for managing offline instrumentation: <instr>, <merge>, and <report>. In a typical ANT build each <emma> tag acts as a container for an arbitrary sequence of sub-tags. This design allows for a simple form of build flow control, whereby entire sequences of EMMA commands can be disabled at a single point.

Let's go back to the starting point of the previous section and assume that you have a build.xml file with EMMA tasks imported and the following build infrastructure created:

  <!-- root directory for the example source code: --> 
  <property name="src.dir" value="${basedir}/src" />

  <!-- javac class output directory: -->
  <property name="out.dir" value="${basedir}/out" />

  <!-- output directory used for EMMA work files and coverage reports: -->
  <property name="coverage.dir" value="${basedir}/coverage" />

  <target name="init" >
    <mkdir dir="${out.dir}" />
    <path id="run.classpath" >
      <pathelement location="${out.dir}" />
    </path>
  </target>

  <target name="compile" depends="init" description="compiles the example source code" >
    <javac debug="on" srcdir="${src.dir}" destdir="${out.dir}" />
  </target>

  <target name="run" depends="init, compile" description="runs the examples" >
    <java classname="Main" classpathref="run.classpath" >
 </target>

In a real world project the actual application could be either an end user application or your test framework driver. Adding offline coverage instrumentation and reporting to this build is not much harder than it was in the command line tools case, in Section 2.3, “Offline mode: separating instrumentation and execution”. All you need to do is sandwich <java> (or your test framework driver, or anything that can run on Java classes) between EMMA's <instr> and <report>:

  <target name="emma" description="turns on EMMA instrumentation/reporting" >
    <property name="emma.enabled" value="true" />
    1<!-- EMMA instr class output directory: -->
    <property name="out.instr.dir" value="${basedir}/outinstr" />
    <mkdir dir="${out.instr.dir}" />
  </target>

  <target name="run" depends="init, compile" description="runs the examples" >
    <emma enabled="${emma.enabled}" >
      <instr instrpathref="run.classpath"2
             destdir="${out.instr.dir}"	
             metadatafile="${coverage.dir}/metadata.emma"
             merge="true"
      />
    </emma>

    3
    <java classname="Main" fork="true"4 >
      <classpath>
       5<pathelement location="${out.instr.dir}" />
        <path refid="run.classpath" />
        <path refid="emma.lib" />
      </classpath> 
      <jvmarg value="-Demma.coverage.out.file=${coverage.dir}/coverage.emma" />6
      <jvmarg value="-Demma.coverage.out.merge=true" />7
    </java>

    <emma enabled="${emma.enabled}" >
      8<report sourcepath="${src.dir}" >
        <fileset dir="${coverage.dir}" >
          <include name="*.emma" />9
        </fileset>

        <txt outfile="${coverage.dir}/coverage.txt" />
        <html outfile="${coverage.dir}/coverage.html" />
      </report>
    </emma>
  </target>

When EMMA instrumentation is enabled via emma.enabled build property, the sequence of logic here is as follows:

1

Again, there is a emma helper target to set emma.enabled to true. Additionally, this target defines ${out.instr.dir} property for coverage-instrumented output. It is important that this property exist only when emma.enabled=true, as you will see later.

2

EMMA's offline instrumentor executes and copies instrumented classes into ${out.instr.dir}. Class metadata is dumped into a metadata.emma file. (Note that <instr> accepts the same run.classpath path element reference as the original build: this is what makes EMMA so easy to integrate with ANT.)

3

The application runs with instrumented classes.

4

In version 2.0, EMMA's runtime coverage data is dumped by a JVM exit handler and for this to happen <java> needs to be forked.

5

As in the command line case, the instrumented classes need to be first in the classpath. Note that this only happens when ${out.instr.dir} property has been defined by emma helper target. Also, <java> needs to have emma.jar in its classpath (recollect the path reference created in Section 3.1, “Adding EMMA tasks to your ANT build”).

6

For certainty, <java> is configured with an explicit filename that accepts runtime coverage profile data.

7

Each time you run, do you want to accumulate coverage data or discard previous results? The default is the former, which is what is forced explicitly above. Note, however, that you could set coverage.out.merge to false and make EMMA delete the previous coverage dump file before creating a new one.

8

EMMA report processor executes.

9

The report processor combines the class metadata and runtime coverage profile to produce a couple of reports.

Overwrite mode

EMMA can do "in place" instrumentation (overwrite mode), whereby the classes and jar files are overwritten with their instrumented versions. However, this is easy to abuse, so the build above is being careful and creates a separate directory for coverage-instrumented output.

Let's see the new build in action. Again, code coverage is turned on only if emma target appears on ANT command line before any run targets:

>ant emma run
Buildfile: build.xml

emma:

init:
    [mkdir] Created dir: .../examples/out

compile:
    [javac] Compiling 4 source files to .../examples/out

run:
[emma.instr] processing instrumentation path ...
[emma.instr] instrumentation path processed in 200 ms
[emma.instr] [3 class(es) instrumented, 0 resource(s) copied]
[emma.instr] metadata merged into [.../coverage/metadata.emma] {in 31 ms}
     [java] EMMA: collecting runtime coverage data ...
     [java] main(): running doSearch()...
     [java] main(): done
     [java] EMMA: runtime coverage data written to [.../coverage/coverage.emma] {in 15 ms}
[emma.report] 2 file(s) read and merged in 0 ms
[emma.report] writing [txt] report to [.../coverage/coverage.txt] ...
[emma.report] writing [html] report to [.../coverage/coverage.html] ...

BUILD SUCCESSFUL
Total time: 7 seconds

Instrumenting just the right classes

Unlike some other tools, EMMA's design is based around filtering for the right set of classes at instrumentation time. Doing so allows EMMA to scale to enterprise size projects and ensures the best performance throughout all three offline stages: instrumentation, execution, and reporting. To select a subset of classes to be processed, you can use two complementary techniques:

  1. segment your ANT path elements well, do not lump everything into just one path. Specifically, keep third-party libraries, your application classes, and testcase classes in separate path elements. It will be easy to combine them when needed and code coverage will be easier because you will have just the right path element to use as <instr>'s instrpath attribute or nested element: your application classes.

  2. additionally, you can give <instr> several <filter> nested elements, each potentially containing a list of class name inclusion/exclusion patterns. This will allow you to zoom in on just the right part of your application. And adding an ANT command-line override for one of those will allow every developer on the team to narrow things down to their own module. See the exact ANT syntax for specifying coverage filters in the reference manual.

Note that your build can contain several instrumentation and execution stages and <report> will happily merge all of the results in memory before generating the reports. To merge all files on disk (for maintenance and disk storage reasons) you can use <merge> sub-task:

  <target name="merge" description="demonstrates dump file merging" >
    <emma>
      <merge outfile="${coverage.dir}/session.emma" >
        <fileset dir="${coverage.dir}" >
          <include name="*.emma" />
        </fileset>
      </merge>
    </emma>
  </target>
In EMMA's offline mode, you are in complete control of mixing and matching metadata and coverage data from different application runs. You can instruct all tools to merge all data in the same file or keep everything in separate file repositories. EMMA tools default to merge=true output file mode for metadata and runtime coverage data, but properties exist to alter this behavior. See Chapter3, EMMA Property Reference in the reference manual for full details on EMMA configuration.

To summarize, an existing build.xml can be converted to use EMMA's offline instrumentation mode by following these steps:

  1. add EMMA task definitions

  2. add the necessary <instr> tasks, making sure that the application classes are instrumented before they are used at runtime

  3. configure classpaths and coverage inclusion/exclusion filters such that only your application classes, not third-party libraries or testcases, are instrumented

  4. make sure the instrumented classes will be prepended to your application's runtime classpath (that is, if you are not packaging them as EJBs, a web app, etc instead)

  5. add a <report> task that aggregates class metadata and runtime coverage profiles for reporting as needed

  6. make sure there is a way to turn coverage instrumentation on and off (you can use either the existing ANT solutions for that or the enabled attribute on all EMMA tasks)

Further reading. This has been a quick intro to EMMA's offline instrumentation tools for ANT. For further details read the reference manual starting with Section3, <instr>/instr.