<?xml version="1.0" encoding="ISO-8859-1"?>
<document>
<head>
    <name>Integrating GroboCoverage With Complex Build Environments</name>
    <doc-version>$Date: 2004/04/17 08:24:40 $</doc-version>
    <author>Matt Albrecht</author>
</head>
<body>

<section>Overview</section>

<p>
This document attempts to describe what changes to the build file need
to happen before you can get code-coverage reports with GroboCoverage.
</p>
<p>
The document will follow the generation of coverage numbers for an EJB
site that uses <a href="http://jakarta.apache.org/cactus/index.html">Cactus</a>
to execute its JUnit tests.  For simplicity, this will modify the sample
application that comes packaged with Cactus (version 1.5, J2EE 1.2).
</p>
<p>
You can see the original version <a href="cactus-sample-build.xml.txt">here</a>,
and the coverage-enabled version
<a href="cactus-sample-build-coverage.xml.txt">here</a>.
</p>


<section>Setup</section>
<p>
You can download the Cactus package from
<a href="http://jakarta.apache.org/site/binindex.cgi">the Jakarta binaries
page</a>.  The sample application is located in the
<code>jakarta-cactus-12-1.5/samples/servlet</code> directory.
</p>
<p>
You need to first copy the GroboCoverage libraries
(GroboCodeCoverage-1.1.0-ant.jar and GroboCodeCoverage-1.1.0-runtime.jar)
into the <code>jakarta-cactus-12-1.5/lib</code> directory so that our
modified build file can reference it.
</p>

<p>
The build file will need more target directories:
<pre>
  &lt;property name="target.classes.coverage.dir"
      location="${target.classes.dir}/coverage"/&gt;
  &lt;property name="target.coverage.dir"
      location="${target.dir}/coverage"/&gt;
  &lt;property name="target.coveragereports.dir"
      location="${target.dir}/coverage-reports"/&gt;
</pre>
We also need to add a reference to the GroboCoverage runtime library:
<pre>
  &lt;property name="grobocoverage.jar"
      location="../../lib/GroboCodeCoverage-1.1.0-runtime.jar"/&gt;
</pre>
Then, right after the Cactus taskdef, we'll define the additional coverage
tasks:
<pre>
  &lt;taskdef resource="ant-grobocoverage.properties"
        classpath="../../lib/GroboCodeCoverage-1.1.0-ant.jar" /&gt;
</pre>
</p>
<p>
We also need a new target for post-compiling the Java class files:
<pre>
  &lt;!-- Instruments the java sources --&gt;
  &lt;target name="postcompile.java" depends="compile.java"&gt;
    
    &lt;mkdir dir="${target.classes.coverage.dir}"/&gt;
    &lt;grobo-instrument logdir="${target.coverage.dir}"
        destdir="${target.classes.coverage.dir}"
        logger="fast"&gt;
      &lt;fileset dir="${target.classes.java.dir}" /&gt;
      &lt;measure type="linecount" /&gt;
    &lt;/grobo-instrument&gt;
  &lt;/target&gt;
</pre>
which requires the "compile" target to change:
<pre>
  &lt;target name="compile" depends="compile.java, compile.cactus, postcompile.java"
      description="Compile the sources"/&gt;
</pre>
and the "test.prepare" target to also change its dependencies:
<pre>
  &lt;target name="test.prepare" 
      depends="war, compile.cactus, postcompile.java, test.prepare.logging"&gt;
</pre>
</p>
<p>
Let's go ahead and add in the report generation steps after the
&lt;junitreport&gt; tasks have run:
<pre>
    &lt;grobo-report logdir="${target.coverage.dir}"&gt;
      &lt;source destdir="${target.coveragereports.dir}" removeempty="true"
          srcdir="${src.dir}" title="Sample Cactus Coverage Report" /&gt;
    &lt;/grobo-report&gt;
</pre>
This puts the source-linked report into the "target/coverage-reports"
directory.  This means that the report directory must already exist.  So,
at the end of the "test.prepare" target, add the lines:
<pre>
    &lt;!-- Prepare the directories for the coverage reports --&gt;
    &lt;mkdir dir="${target.coveragereports.dir}"/&gt;
</pre>
which will keep an I/O exception from being thrown during the report
generation phase.
</p>


<section>Augmenting The War File</section>
<p>
So far, the changes to the build file have post-compiled the Java class
files and generated a report.
</p>
<p>
The hard part still remains: alter the deployed war file so that it uses
the post-compiled class files before it uses the Java class files.
</p>
<p>
Fortunately, this example "cactifies" the war file, so that the unit tests
use a different war file than the distributable one.
</p>
<p>
Also, GroboCoverage provides a task that helps modify existing zip files.
Add this immediately after the <code>&lt;cactifywar&gt;</code> task runs:
<pre>
    <!-- +++ Create the code-coverage-enabled WAR file -->
    &lt;grobo-rezip&gt;
        &lt;alterWar src="${target.dir}/${project.name.file}-cactified.war"
            dest="${target.dir}/${project.name.file}-cactified-covered.war"&gt;
          &lt;classes dir="${target.classes.coverage.dir}" /&gt;
          &lt;lib file="${grobocoverage.jar}" /&gt;
        &lt;/alterWar&gt;
    &lt;/grobo-rezip&gt;
</pre>
In this case, all we're modifying is the WAR file itself; a judicious use
of a <code>&lt;zip&gt;</code> task could have accomplished the same thing.
However, if instead of a WAR file, it used an EAR file, we'd have to unzip
the EAR, alter the WAR, and rezip the EAR.  Not too much fun.
</p>
<p>
Or, we could have put these classes and lib files into the
<code>&lt;cactifywar&gt;</code> task.  However, the rezip task was used
for the sake of showing how to integrate GroboCoverage into complex sites,
not just Cactus sites.
</p>
<p>
Then, we need to modify the <code>&lt;cactus&gt;</code> task.  First, we replace the
referenced war file:
<pre>
    &lt;cactus warfile="${target.dir}/${project.name.file}-cactified-coverage.war"
</pre>
then alter the classpath so that it uses the post-compiled classes before the
originals, and includes the GroboCoverage library file:
<pre>
      &lt;classpath&gt;
        &lt;path refid="project.classpath"/&gt;
        &lt;pathelement location="${httpunit.jar}"/&gt;
        &lt;pathelement location="${nekohtml.jar}"/&gt;
        &lt;pathelement location="${target.classes.coverage.dir}"/&gt;
        &lt;pathelement location="${target.classes.java.dir}"/&gt;
        &lt;pathelement location="${target.classes.cactus.dir}"/&gt;
        &lt;pathelement location="${log4j.jar}"/&gt;
        &lt;pathelement location="${grobocoverage.dir}"/&gt;
      &lt;/classpath&gt;
</pre>
(yes, I chopped out that clover.jar reference; yuck!)
</p>


<section>What We Learned</section>
<p>
What did we learn from this lesson?  If you attempt to gather code-coverage
numbers from a deployed process, you need to make another deployable file
using the post-compiled classes, rather than the originals.  Also, to
ensure that the client-side part of the tests have coverage numbers gathered,
the same classpath steps must be taken as usual.
</p>


</body>
</document>
