JaVa
   

jcoverage Primer

There are three ways to run jcoverage on your project: from the command-line, as an Ant script, or as a Maven plugin. We are going to cover how to run and interpret jcoverage reports as an Ant script and cover any issues with running it as a Maven plugin.

jcoverage as an Ant task

Adding jcoverage reports to your Ant buildfile is relatively easy. First you need to download the jcoverage/gpl JAR file and its third-party JAR files to your local hard drive. Place these files where your Ant project can find it— typically this means that you can add it to your project's lib directory and reference it using your Ant buildfile (for more information about Ant, see ). Once you have done that, you can add the JAR file to your build.xml:

<path id="jcoverage.path">
 <fileset dir="${lib.dir}">
 <include name="jcoverage.jar"/>
 <include name="log4j*.jar"/>
 <include name="bcel.jar"/>
 <include name="jakarta-oro*.jar"/>
 <include name="java-getopt*.jar"/>
 </fileset>
</path>
<taskdef classpath="jcoverage.path" resource="tasks.properties"/>


This adds the following tasks to your Ant build file:

jcoverage puts all the information that it uncovers into a serialized file (.ser). You can specify additional files that can be merged together for different testing types (such as unit and functionality testing). In this way you create one comprehensive coverage report, instead of dealing with multiple ones.

Adding the Necessary Pieces to Your buildfile

Once you have added the jars as classpath references, you then add the taskdef element (as seen above). The next step is to make sure that you are running your JUnit tests correctly. This means that we need to instrument the classes first so that jcoverage can collect the information that it needs to build a report. This requires some setup first as we need to tell Ant where we want all the files to go first.

<property name="build.dir" value="${basedir}/build/"/>
<property name="build.classes.dir" value="${build.dir}/classes"/>
<property name="build.test-classes.dir" value="${build.dir}/test-classes"/>
<property name="build.instrumented-classes.dir" value="${build.dir}/instrumented-classes"/>
<property name="build.coverage.dir" value="${build.dir}/coverage"/>
<property name="build.reports.dir" value="${build.dir}/reports"/>
<property name="lib.dir" value="${basedir}/lib"/>
<property name="src.dir" value="${basedir}/src/java"/>
<property name="test.dir" value="${basedir}/src/test"/>


Here is a brief description of the properties shown above:

Ok, so we have now defined all of our directories. Just like any build file we need to specify an init target that will create some of these directories that we need.

<target >
 <mkdir dir="${build.dir}"/>
 <mkdir dir="${build.classes.dir}"/>
 <mkdir dir="${build.test-classes.dir}"/>
 <mkdir dir="${build.coverage.dir}"/>
 <mkdir dir="${build.instrumented-classes.dir}"/>
 <mkdir dir="${build.reports.dir}"/>
</target>


Next we need to compile our source files and then instrument them.

<target description="compile all classes">
 <javac srcdir="${src.dir}" destdir="${build.classes.dir}" failonerror="yes" debug="yes"/>
</target>
<target description="Add jcoverage instrumentation">
 <instrument todir="${build.instrumented-classes.dir}">
 <ignore regex="org.apache.log4j.*"/>
 <fileset dir="${build.classes.dir}">
 <include name="**/*.class"/>
 </fileset>
 </instrument>
</target>


This is fairly straightforward, but some explanation is warranted. First we call compile, which compiles the java files into class files. We then have the instrument target which calls its own task of instrument. The instrument task takes a todir argument to tell jcoverage where we wish to place the modified files—it's important that this be done to a separate directory as you don't want to distribute instrumented classes to your users (they are only meant for test coverage purposes). The body of the tag takes an Ant fileset specifying which classes to instrument. You can also specify packages to ignore using the ignore with a regex option; in this case we are telling jcoverage to ignore any line with a reference to log4j. Now that we have instrumented our classes we want to run our unit tests on them.

<target description="Unit test the app">
<javac srcdir="${test.dir}" destdir="${build.test-classes.dir}" failonerror="yes" debug="yes">
 <classpath ref />
 <classpath location="${build.classes.dir}"/>
 </javac>


First we compile the test classes to the test-classes directory under build. Next we run the tests using junit. When running the tests we need to specify the instrumented classes prior to the real classes so that the instrumented classes are called first.

 <junit fork="yes" dir="${basedir}" errorProperty="test.failed" failureProperty="test.failed">
 <!--
 note the classpath order, instrumented classes are before the
 original (uninstrumented) classes.
 -->
 <classpath ref />
 <classpath location="${build.instrumented-classes.dir}"/>
 <classpath location="${build.classes.dir}"/>
 <classpath location="${build.test-classes.dir}"/>
 <!--
 the instrumented classes reference classes used by the
 jcoverage runtime.
 -->
 <classpath refid="jcoverage.path"/>
 <formatter type="xml"/>
 <test name="${testcase}" todir="${build.reports.dir}" if="testcase"/>
 <batchtest todir="${build.reports.dir}" unless="testcase"> <fileset dir="${build.test-classes.dir}">
 <include name="**/*Test.class"/>
 </fileset>
 </batchtest>
 </junit>
</target>


This executes a standard unit test, but because we are using the instrumented classes it requires that we have the jcoverage jars in the testing classpath; otherwise our tests will fail. Upon completion of the unit testing, jcoverage will have collected all of its data in jcoverage.ser, which it will then use to create the coverage reports:.

<target description="HTML and XML coverage reports can be found in build/coverage">
 <report srcdir="${src.dir}" destdir="${build.coverage.dir}"/>
 <report srcdir="${src.dir}" destdir="${build.coverage.dir}" format="xml"/>
 <echo>
jcoverage reports have been generated.
The HTML report is ${build.coverage.dir}/index.html The XML report is ${build.coverage.dir}/coverage.xml
 </echo>
</target>


jcoverage creates two kind of reports: HTML and XML. In this example we specified that we want to see both. Now that we have built our reports, what do they look like? Here they are—the first figure shows the overall coverage report, and the second shows a class coverage report:

Java Click To expand Java Click To expand

As you can see with our test class, we do not have 100% coverage, this is intentional to show what it looks when you don't have everything covered properly. We will examine what to do a little later in our case study.

jcoverage as a Maven Plugin

Installing the jcoverage Maven plugin is relatively easy; by default jcoverage is included as one of the optional plugins. If you want to use the latest jcoverage plugin, you will need to manually download it from http://maven.apache.org/reference/plugins/jcoverage/. Please follow the manual plugin installation instructions found in , “Managing Projects with Maven” of this tutorial. Once you have installed the plugin version you wish to use, you can set up jcoverage to be used in your Maven project. As with the Ant build file, there are a number of properties we can use to configure the plugin.

To call jcoverage you simply type

maven jcoverage or jcoverage:html-report


which will generate the HTML report that we saw above in the Ant section. To include this as one of the default reports for your project, you will need to add the following to the reports section of your Maven project.xml file:

<report>maven-jcoverage-plugin</report>


Now when you generate your Web site, this will automatically include the jcoverage reports for your project.


JaVa
   
Comments