Code coverage

Author: Kasper B. Graversen, 05/12/07
Keywords: ANT, Build script
Abstract: This article introduces the term "code coverage" and show how you will get started using the free code coverage tool "Emma".
subscribe to my RSS feed


Bookmark and Share


Code coverage

"Code coverage" is a measure of how many percent of your code is executed during the execution of test cases. While it would seem that proper code coverage must converge the 100%. In practice, however, striving for such a number is both infeasible and impractical for most cases. Further more, a code coverage of 100% is by no means a guarantee that the code is bug-free.

The pragmatic stance to testing should be a combination of the following
  1. Testing should be a terse specification of the behavioral requirements of the code you are about to write.
  2. Testing should be applied in the dosage that enables you to feel confident of the code you have been producing.
  3. Testing should act as a form of documentation on how to use a piece of code.
As you can see this means the concept of testing can be applied both prior to coding and after having coded something. "Code coverage" is in itself just a number, say 68% and as such doesn't really carry any value. The value added by using a code coverage tool such as Emma is the ability to inspect code and visually verify which lines actually have been tested and which haven't. Based on this information it can be decided if further tests are required. My personal experience has been that initially when writing tests, you focus your tests on the "success paths", that is, ensuring upon valid input, that valid output is given. When your testing skills mature (and this takes time and practice), you'll focus just as much on ensuring correct behaviour upon invalid input.

My personal experience with code coverage is that you get the same warm fuzzy feeling similar when I starting doing test-driven development and test infected code. But more so. Not only can you be confident making changes and in the product you are delivering, with code coverage, you are able to asses all the cases you forgot to test.

Why not 100% code coverage

So why is it not worth striving for the 100% test coverage? The main argument is that its a waste af time. Tests take time to write. Tests takes time to refactor when the code changes. Tests takes time to execute. Hence, you should only test the parts of your code where you gain leverage. The following are examples of code that I in the general prefer not to test
  • Accessor methods / value objects.
  • Overloaded constructors
  • User interface code

Code coverage with EMMA and ANT

EMMA is a tool to measure code coverage. How EMMA does its business is by instrumenting your classes such that the execution of a line gets recorded in an emma log file which subsequently is used to generate code coverage reports. While the below looks quite trivial it can be tricky to get working in practive. The ANT script does the following
  • Setup paths for the code coverage report, the destination of the instrumented bytecode files and finally where Emma is installed.
  • Then emma.filter is set to denote the classes to cover (in this case org.supercsv)
  • Build all the classes with debug options into the coverage dir
  • Run the emma instrumentation
  • Run JUnit
  • Generate the code coverage report
The below code is taken from the Super CSV project build.xml
    <target name="testcoverage" depends="-init_test">
         <!-- directory which emma coverage reports will be written to -->
        <property name="dir.coveragereport" value="${basedir}/web/emmareports/" />
        <mkdir dir="${dir.coveragereport}"/>
        <delete file="${dir.coveragereport}/coverage.emma" />
        <delete file="${dir.coveragereport}/metadata.emma" />
        <!-- directory that contains emma.jar and emma_ant.jar -->
        <property name="emma.dir" value="${dir.lib}" />

        <!-- Set emma.lib to refer to the list of EMMA jar files -->
        <path id="emma.lib" >
            <fileset dir="${emma.dir}">
                <include name="*.jar"/>
            </fileset>
        </path>

        <!-- Load <emma> and <emmajava> custom tasks so that they can be used in ANT -->
        <taskdef resource="emma_ant.properties" classpathref="emma.lib" />
        <property name="emma.enabled" value="true" />


        <!-- this property, if overriden via -Demma.filter=<list of filter specs>
         on ANT's command line, will set the coverage filter; by default,
         all classes found in 'emma.coverage.classes' pathref will be instrumented:
        -->
        <!-- must use filtering -->
        <property name="emma.filter" value="org.*" />

        <!-- compile files -->
        <antcall target="-compile"/>


        <!-- Define which classes will be reported in the coverage reports (by default, we will include all classes and assume -->
        <!-- that your project's output folder is target/classes -->
        <path id="emma.coverage.classes" >
            <pathelement location="${dir.build}" />
        </path>

        <!-- EMMA INSTRUMENTATION -->
        <!-- Instrument the classes, this takes the normal classes, and makes instrumented classes instead -->
        <emma enabled="${emma.enabled}" >
            <instr instrpathref="emma.coverage.classes"
                 metadatafile="${dir.coveragereport}/metadata.emma"
                 merge="true"
                mode="overwrite" verbosity="verbose"
            >
                 <!-- exclude classes with a "Test" in the name: -->
                 <filter excludes="*Test" />
                 <filter value="${emma.filter}" />
            </instr>
        </emma>

        <!-- before test run, copy test files and compile them -->
        <antcall target="-compile_tests"/>

        <!-- run test -->
        <junit haltonfailure="true" printsummary="true" fork="true" forkmode="once">
            <batchtest>
                <fileset dir="${dir.build}" includes="**/*Test.class"/>
            </batchtest>
            <formatter type="brief" usefile="false" />
            <classpath>
                <path refid="classpath" />
                <pathelement location="${dir.build}" />
            </classpath>

            <jvmarg value="-Demma.coverage.out.file=${dir.coveragereport}coverage.emma" />
            <jvmarg value="-Demma.coverage.out.merge=false" />
        </junit>


        <!-- generate test coverage report -->
        <!-- if enabled, generate coverage report(s): -->
        <emma enabled="${emma.enabled}" verbosity="verbose">
            <report
                  sort="+name,+block,+method,+class"
                  metrics="method:80,block:80,line:80,class:100"
            >
                <sourcepath >
                      <dirset dir="${dir.tmp_src}" >
                      </dirset>
                </sourcepath>

            <!-- collect all EMMA data dumps (metadata and runtime)
                 [this can be done via nested <fileset> fileset elements
                 or <file> elements pointing to a single file]:
            -->
            <fileset dir="${dir.coveragereport}" >
                <include name="*.emma" />
            </fileset>

            <!-- for every type of report desired, configure a nested
                 element; various report parameters
                 can be inherited from the parent <report>
                 and individually overridden for each report type:
            -->
                <html outfile="${dir.coveragereport}/index.html"
                depth="method"
                columns="name,class,method,block,line"
            />
            </report>
        </emma>

        <antcall target="-post_clean"/>
    </target>

Aftermath

When you have this up and running, you sholud experiment with different report output. Specifically, you probably want to adjust the code coverage such that it is low during development (e.g. 20), while at the milestone deadline, increasing it to 80% or whatever you find suitable. This can be done in metrics="method:80,block:80,line:80,class:100" in the report generation.

While EMMA is a nice free tool, it has its limits. Specifically, there are two features you may find in competing products that EMMA currently does not provide.
  • It does not record your test-coverage over time. Hence you cannot automatically trace general improvements of your test coverage
  • There is no instantanious feedback in your development tool. Instead you have to run this script and consult your browser for a report. For Eclipse, there is a nice free tool (based on EMMA) called ???.
  • There is no integration with ANT such that the coverage-task fails if the coverage is too low. This would be useful in ensuring a company test-coverage policy. However, too strict rules may easily get more in the way than do good. Another tool Cubertura has such a feature, but seems (at present) to be lacking block coverage.



Comments

If you have any comments to this article, please drop me a mail at firstclassthoughts at gmail dot com please indicate if I can't publish whole or parts of your comment on the site.


If you like this site consider subscribing to my RSS feed or how about subscribing by Email.


Help spread the word

Share this post on your favorite social bookmarking sites:
If you enjoyed this article, found it thought provoking, educative or otherwise good, please link to this page from your page or social bookmarking page. If you have any texts you think are worth publishing on First Class Thoughts, don't hesitate to send me a mail! Quality always welcome.


Bookmark and Share


The most recent contributions
28/07/09 Magic in mathematics II Fun with the number cyclic numbers, and specifically with 142857 as it is the smallest of such numbers.
13/07/09 My top 8 time-saving Firefox shortcuts This article presents my favorite top 8 time-saving shortcuts in Firefox 3.0 and Firefox 3.5. Get to know these and you'll be saving a lot of time. They have been ordered by "the element of most surprise"
20/05/09 Board Game Jungle speed / Arriba Review of the cool game "Jungle Speed" aka. "Arriba".
16/05/09 Danish Twin words "Twin words" are words that not only have multiple meanings, they must be composed next to each other in meaningful sentences. This article explores the concept of twin words.
Nothing of interest? Try browsing the entire article archive...