EMMA ANT使用

http://emma.sourceforge.net/userguide/ar01s03.html


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, inSection2, “Getting Started (command line)”. Additionally, the ANTbuild.xmlfiles 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 inexamples/srcdirectory of EMMA distribution is used for all examples in this tutorial. EMMA distribution also includes two sample ANT buildfiles,build-onthefly.xmlandbuild-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 bothemma.jarandemma_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 yourbuild.xml:

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

  <path id="emma.lib" >
    <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 inexamples/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 EMMAemmaruncommand 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 itsenabledattribute is set tofalse:

  <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 insertemmabefore any run targets on ANT's command line, you enable on-the-fly coverage instrumentation and reporting (but ANT commands withoutemmacontinue 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 isallwhich 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. SeeChapter3, EMMA Property Referencein 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 setfullmetadatatask attribute totrue. Here is an example that also adds some extra reports and makes sure the HTML report generator has access to the source code by settingsourcepath="${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>'semmaclasspathattribute instead of the usualclasspath:

    <emmajava enabled="${emma.enabled}" libclasspathref="allmylibs.path" 
              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"
    >
      <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 existingbuild.xmlcan 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 seeSection2, <emmajava>/emmarunin 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 abuild.xmlfile 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





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值