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 -------------------------------------------------------------------------------
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>:
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:
add EMMA task definitions
replace the necessary invocations of <java> with <emmajava>
configure coverage paths and inclusion/exclusion filters
configure coverage reports
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.