Yesterday I was reading other blogs and I came across a code coverage product. About 2 years ago I also was looking for a free opensource code coverage tool. It was GroboCodeCoverage that I found. This tool just did not cut it for me. To much effort to get it to work for my kind of architecture, which consits of multiple projects. Each layer has it’s own project (web,business,domain,data access). And I ran into performance problems very often. So when I heard about another framework I wanted to give it a try. Since I am using luntbuild as a build manager, I also want to integrate the results into luntbuild. The integration must be simular to the junit integration.

Now what is that tool I am talking about? I am talking about cobertura. Via the faq of cobertura I also found emma. I choose Cobertura for the easy installation and use, but most of all for the way the reports are created. I like them much more than the reports of emma. I the future I do want to have a look at emma to see if performance is different for the tools.

Sorry for the long introduction, now we are going to install and use cobertura. First I installed version 1.4, but I ran into problems while using it with multiple components into one project. You have to merge the result files of the coverage measurements. This only worked correct in the latest greatest cvs version.

Have a look at another blog item of mine that gives you a better option of presenting the link to the reports : extending luntbuild with cobertura reports


cvs -d :pserver:anonymous@cvs.sourceforge.net:/cvsroot/cobertura login
(Just hit enter for the password)
cvs -z3 -d :pserver:anonymous@cvs.sourceforge.net:/cvsroot/cobertura checkout -P cobertura

cd into the cobertura directory and run ant with the coverage jar options

ant coverage jar

This creates a cobertura.jar file.

Before we can use ant we need to add some jars to the ant lib folder. These jars come with the cobertura sources.
jakarta-oro-2.0.8.jar asm-2.0.jar log4j-1.2.9.jar java-getopt-1.0.9.jar ccl.jar javancss.jar

Now we need to configure our ant build scripts so that the instrumentation (changing the byte code of the classes) takes place. After that we need to run the unit test with the correct classpath and finally run the reports task of cobertura. How does this look in our build script:


<taskdef classpath=”cobertura.jar” resource=”tasks.properties” />

<target name=”compiletest” description=”Compile all test code, and instrument classes for coverage”>
… omitted code to compile test cases for clarity …

  <cobertura-instrument todir=”${dir.component.coverage.instrument}”>
    <ignore regex=”util.*” />
    <fileset dir=”${dir.component.build}”>
      <exclude name=”**/Test*”/>
      <include name=”**/*.class”/>
    </fileset>
  </cobertura-instrument>

  <copy todir=”${dir.component.coverage.src}”>
    <fileset dir=”${dir.component.src.java}” includes=”**/*.java” />
  </copy>
</target>

This block of code instruments all classes in the build folder except for the test cases, in the end the sources are copied to a central directory. The sources are used to show you the lines that have test coverage. This is a work around, a next release will enable you to have multiple source directories in the report task.

The classes are instrumented, now we must put them on the unit test classpath, we also need the cobertura.jar file at runtime on the classpath.

<junit printsummary=”on” fork=”true” forkmode=”once” haltonfailure=”false” failureproperty=”test.failed” showoutput=”true”>
  <sysproperty key=”net.sourceforge.cobertura.datafile” file=”${basedir}/cobertura.ser” />
  <classpath>
    <pathelement path=”${dir.component.coverage.instrument}”/>
    <path refid=”project.classpath”/>
    <pathelement path=”${compiler.classpath}”/>
    <pathelement path=”${dir.component.build}”/>
    <fileset dir=”${dir.component.lib}”>
      <include name=”*.jar”/>
    </fileset>
  </classpath>
  <formatter type=”xml” usefile=”true”/>

  <batchtest todir=”${dir.project.junit.report}”>
    <fileset dir=”${dir.component.src.test}”>
      <include name=”**/Test*.java”/>
    </fileset>
  </batchtest>
</junit>

Important in this code are the sysproperty tag, this helps the unit test to find the just data file. Another important thing is to put the instrumented classes on the classpath before the normal classes. The directory for instrumented classes is obtained via the property ${dir.component.coverage.instrument}. The cobertura.jar file is in the lib folder ${dir.project.lib} that is added to the classpath via the project.classpath.

After all unit tests have been executed we have cobertura.ser files for all components. We first need to make one data file and then run reports on this merged datafile. This is done by the following piece of script.

<target name=”test” depends=”distribution,runtests” description=”Runs the junit report”>

… omitted code to execute junitreport for clarity …
  <cobertura-merge>
    <fileset dir=”${basedir}/”>
      <include name=”*/cobertura.ser”/>
    </fileset>
  </cobertura-merge>
  <cobertura-report srcdir=”${dir.project.coverage.src}” destdir=”${coverageHtmlReportDir}”/>
</target>

Important in this code is the merge tag, this looks at all subfolders for cobertura.ser files and merges these into a new cobertura.ser file. Another important part for luntbuild integration is the parameter ${coverageHtmlReportDir}. The value for this parameter is provided by luntbuild and gives the location for storing the report files.

The next image gives an example of the report that is created for my sample application:
[img]/images/ScreenshotCoverageReport.png[/img]
Now we want those coverage reports in luntbuild. For starter, this can propobly be done different in the meaning of correct. What I have done is a hack, but for me it works. Have a look at another blogitem of mine for a better way of integrating the cobertura reports and luntbuild. Actually there is two things we should do:
1. Place the report files in the correct directory, this is done by ant but we need to pass the right parameter plus value.
2. Show a link on the website that directs to the coverage report.

Lets start with the first item, this can be done by configuring the builder. Open your luntbuild project configuration. Go to the builder tab and put an extra variable in the Build properties box:

coverageHtmlReportDir=”${build.publishDir}/coverage_html_report”

This parameter is used by ant to find the luntbuil publish directory.

Now we want to add a link to the luntbuild Build view page. This done by adding some lines to the file LUNTBUILD_HOME/WEB-INF/BuildViewer.html

… more here …
<td width=”10%” align=”center” class=”buildTitleRight”>
  <span jwcid=”@Conditional” condition=”ognl:junitHtmlReport!=null”>
    <span jwcid=”@GenericLink” href=”ognl:’statefulPublish/coverage_html_report/index.html'” title=”coverage report”>
coverage report
    </span>
  </span>
</td>
<td width=”10%” align=”center” class=”buildTitleRight”>
  <span jwcid=”@Conditional” condition=”ognl:junitHtmlReport!=null”>
    <span jwcid=”@GenericLink” href=”ognl:’statefulPublish/’+ junitHtmlReport” title=”junit report”>junit report</span>
  </span>
</td>
… more here …

I copied the td for junit, what I wanted was an extra parameter coverageHtmlReport. I did not figure out how to do just that. The following image shows what it is looking like.
ScreenshotLuntbuild
In reply to a question in the comments I have added the complete build.xml files as well. The project I am using cobertura for has modular design. Therefore there is one main build.xml file that is the starting point. There is another build.xml file that contains the generic targets used by the modules. Finally every module has it’s own build.xml file.
build-main.xml
build-targets.xml
build.xml

Code coverage with cobertura and luntbuild