Tutorial: Getting started with Netbeans and JUnit plus Cobertura (Part 2)

Following part 1 which covered the class and JUnit class creation and ended in a suspected successful test.

Part 1 (covering Cobertura setup and execution)

Preparation:

Tutorial:

  • Extract the Cobertura file (named cobertura-1.9.3-bin.zip, 1.9.3 is the actual version at the time of creation of this tutorial)
    You will find 4 library files (jars) that you need to copy somewhere. I copied them into my ANT folder under Netbeans for this tutorial, but I would recommend to copy the files into the lib folder of your project.

    Cobertura Tutorial

    Cobertura Tutorial

    Cobertura Tutorial

    Cobertura Tutorial

  • Add the libraries to our project
    Project Properties|Libraries|Run Test folder
    As I remarked before, here I point to a relative path outside my project folder which is not good practice.

    Cobertura Tutorial

    Cobertura Tutorial

  • Modify the Netbeans project properties file
    There is currently no Cobertura plugin available for Netbeans (at least I am not aware of one, except one on project kenai server, but it’s not implemented yet)
    Open the file explorer view of our project and opent he file project.properties (which is created by Netbeans and updated when we change project settings). For serious projects I recommend to always make a copy before manually changing its content.
    We add 3 lines for our instrumented class files.

    c

    Cobertura Tutorial

    Cobertura Tutorial

    Cobertura Tutorial

    # FOR COBERTURA
    build.instrumented.dir=${build.dir}/instrumented
    build.report.dir=${build.dir}/report
    build.report.cobertura.dir=${build.report.dir}/cobertura
    
  • Modify the Ant build script
    Ant can do a lot, Maven maybe more. I am not an Ant expert, but at least I could bend  my brain around it and figure out how it works. So far I was the lazy Netbeans user “what is ant?”
    I will not explain Ant (curious readers can proceed to ant.apache.org), but you should understand the concept of tasks and dependencies.
    Netbeans creates to build files: a build.xml in your project root and a build-impl.xml in the nbproject subfolder. You are advised to add ant tasks in the build.xml file, the other file is maintained by Netbeans.
    First we need to tell ant to create the instrumented class files (Cobertura add some stuff to each line of our byte code). The instrumented bytecode is kept separately and does not affect our production classes.
    open the build.xml file, it should be empty except some header (that also imports the other buildfile) and some remarks explaining how it works. Right at the end (before the </project>)  we add this

    <property environment="env"/>
    <taskdef classpath="cobertura.jar" resource="tasks.properties"/>
    <target name="-pre-compile-test">
     <delete dir="${build.instrumented.dir}" />
     <delete dir="${build.report.cobertura.dir}" />
     <mkdir dir="${build.instrumented.dir}" />
     <mkdir dir="${build.report.cobertura.dir}" />
     <cobertura-instrument todir="${build.instrumented.dir}">
     <fileset dir="${build.classes.dir}">
     <include name="**/*.class"/>
     </fileset>
     </cobertura-instrument>
    </target>
    

    It is not a new task (there are no dependencies here) but it overrides the task with same name in the build-impl.xml file.

    <    <target name="-post-compile-test">
     <!-- Empty placeholder for easier customization. -->
     <!-- You can override this target in the ../build.xml file. -->
     </target>
    

    Every time we test the whole project this task is called and will create the instrumented class files for us.

  • Modify the class path for test execution
    This is the part which I didnt figure as fast. The cobertura result was created and always showed 0% coverage. You need to tell Netbeans/Ant to use the instrumented classes for the test not the regular ones in your build folder.

    Cobertura Tutorial

    Cobertura Tutorial

    Open the project.properties file again and make sure to add the line ${build.instrumented.dir}:\ before your regular build path.
    Note the entries with ${file.reference.asm-3.0.jar}:\ were added by Netbeans when we added the Cobertura libraries. You could adjust the classpath order using the project properties as well.

    javac.test.classpath=\
     ${javac.classpath}:\
     ${build.instrumented.dir}:\
     ${build.classes.dir}:\
     ${libs.junit_4.classpath}
    ..
    run.test.classpath=\
     ${javac.test.classpath}:\
     ${build.instrumented.dir}:\
     ${build.test.classes.dir}:\
     ${file.reference.asm-3.0.jar}:\
     ${file.reference.asm-tree-3.0.jar}:\
     ${file.reference.cobertura.jar}:\
     ${file.reference.jakarta-oro-2.0.8.jar}:\
     ${file.reference.log4j-1.2.9.jar}
    

    Executing the test for our project now will use the instrumented classes and creates a coverage result files for us (cobertura.ser, NO, you cant open the file in the editor)

  • Modify the build script to convert the result file in human readable websites.
    I do this (breaking the previous rule) in the build-impl.xml file, but it would be fairly easy to migrate this to “our” build.xml file.
    Look for this section

     <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
     <fail if="tests.failed">Some tests failed; see details above.</fail>
     </target>
    

    and ammend it:

     <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
     <fail if="tests.failed">Some tests failed; see details above.</fail>
     <!-- You can disable the html portion if you are using the hudson plugin and rely on the xml -->
     <cobertura-report format="html" srcdir="${src.dir}" destdir="${build.report.cobertura.dir}"/>
     <!-- Used by the hudson plug-in -->
     <cobertura-report format="xml" srcdir="${src.dir}" destdir="${build.report.cobertura.dir}"/>
     <delete file="cobertura.ser" />
     </target>
    
  • Execute the tests and enjoy the results
    You trigger the test for the whole project and your output will be like this

    init:
    deps-jar:
    compile:
    Deleting directory /home/sven/NetBeansProjects/CoberturaDemo/build/instrumented
    Deleting directory /home/sven/NetBeansProjects/CoberturaDemo/build/report/cobertura
    Created dir: /home/sven/NetBeansProjects/CoberturaDemo/build/instrumented
    Created dir: /home/sven/NetBeansProjects/CoberturaDemo/build/report/cobertura
    Cobertura 1.9.3 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
    Cobertura 1.9.3 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
    Instrumenting 1 file to /home/sven/NetBeansProjects/CoberturaDemo/build/instrumented
    Instrumenting 1 file to /home/sven/NetBeansProjects/CoberturaDemo/build/instrumented
    Cobertura: Saved information on 1 classes.
    Cobertura: Saved information on 1 classes.
    Instrument time: 77ms
    Instrument time: 77ms
    compile-test:
    Testsuite: demo.TestMeTest
    Smaller than 5
    Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.099 sec
    
    ------------- Standard Output ---------------
    Smaller than 5
    ------------- ---------------- ---------------
    Cobertura: Loaded information on 1 classes.
    Cobertura: Saved information on 1 classes.
    test-report:
    Cobertura 1.9.3 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
    Cobertura 1.9.3 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
    Cobertura: Loaded information on 1 classes.
    Cobertura: Loaded information on 1 classes.
    Report time: 251ms
    Report time: 251ms
    Cobertura 1.9.3 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
    Cobertura 1.9.3 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
    Cobertura: Loaded information on 1 classes.
    Cobertura: Loaded information on 1 classes.
    Report time: 107ms
    Report time: 107ms
    Deleting: /home/sven/NetBeansProjects/CoberturaDemo/cobertura.ser
    test:
    BUILD SUCCESSFUL (total time: 3 seconds)
    

    You still will end up seeing the JUnit test result pane with “test passed”, but lets go to the report folder in our project and open the index.html file (Ignore the coverage.xml file because it is used by theHudson plugin that we will discuss in part 3)

    Coberture Tutorial

    Coberture Tutorial

    Ops, there is still something in red !

    Corbertura Tutorial

    Corbertura Tutorial

    Cobertura tells us exactly which part of our method was never touched by our tests !

    Corbertura Tutorial

    Corbertura Tutorial

  • Increase the code coverage|
    Lets go back to our project and add test cases

    ..
     @Test
     public void testApp() {
     TestMe tst = new TestMe();
     int res = tst.doSomething(3);
     assertEquals("Correct value", 0, res);
    
     res = tst.doSomething(6);
     assertEquals("Correct value", 2, res);
    
     res = tst.doSomething(11);
     assertEquals("Correct value", -1, res);
     }
    ..
    

    and test again

    Cobertura Tutorial

    Cobertura Tutorial

    Voila ! All lines and branches are covered. 100% (Find my remark later)…GREEN all over.

    Cobertura Tutorial

    Cobertura Tutorial

Resume:
I love this tool. Thanks for creating it. I cant add quality to the source (it is open source) but at least I could create this tutorial for more folks to get started. Use Corbertura !
I will try Corbertura with Hudson in the next part and also try it on web applications.

2 more remark
:
Dont let fool yourself in the assumptions that covering all lines in your codebase really reflects a complete test, you still need to test the business logic of your application against various use cases !
In reality 100% coder coverage is not realistic. The complexity explodes with combination of for/while loops combined with if statements, and also platform dependendant or very exceptional parts might not be possible to be covered. But try your best 🙂
References:
I could not get the tutorial running without using this pre-existing fragments/snippets/ideas and websites

Update (2009-09-25):
There is a problem with the path of Cobertura. The above tutorial only works because the 4 jar files are in the ant folder, which is in the path !  I realized this after testing the project in a different environment.

Advertisements

15 thoughts on “Tutorial: Getting started with Netbeans and JUnit plus Cobertura (Part 2)

  1. Pingback: Tutorial: Getting started with Netbeans and JUnit plus Cobertura and Hudson (Part 3) « The JavaDude Weblog

  2. Hi, I tried to run the test but get the following error:

    “Problem: failed to create task or type cobertura-instrument”

    I think this may be related to the jars not being in the ANT directory, but I don’t know. I am new at using this and I’m not sure where the ANT directory is for NETBEANS. The classpath looks right, so I don’t understand. Please point me in the right direction if you can… thanks!

  3. I am using a Mac and the ant directory is inside a package linked to the NETBEANS app. So, there is no way to add the jars to the ANT directory and they are not working in their own directory in my project. This sucks. I have never had so much trouble getting something to work. Unbelievable. No matter what I do to the classpath, it doesn’t work.

    • I had the same struggle (on Linux), even I believe it is a platform independent problem. I copied it to ../netbeansx.y/java2/ant/bin and it run afterwards. I can share my demo project, maybe some settings different. Let me know.

  4. To solve the “failed to create …” problem, I created a directory antlib directly below my project root, put cobertura.jar and all the libs from the cobertura-1.9.4.1/lib there, and added the changed the build.xml lik follows:

  5. Ooops, my xml was sucked by the html-injection protection. I meant to say:

    <property environment=”env”/>
    <path id=”cobertura.class.path”>
    <fileset dir=”${build.dir}/../antlib”>
    <include name=”**/*.jar”/>
    </fileset>
    </path>
    <taskdef classpathref=”cobertura.class.path” resource=”tasks.properties”/>
    <target name=”-pre-compile-test”>
    <delete dir=”${build.instrumented.dir}” />
    <delete dir=”${build.report.cobertura.dir}” />
    <mkdir dir=”${build.instrumented.dir}” />
    <mkdir dir=”${build.report.cobertura.dir}” />
    <cobertura-instrument todir=”${build.instrumented.dir}” classpathref=”cobertura.class.path”>
    <fileset dir=”${build.classes.dir}”>
    <include name=”**/*.class”/>
    </fileset>
    </cobertura-instrument>
    </target>

  6. Thank you very much for your help.

    Some small issues I faced incase it helps anyone:
    – Hidden spaces can make a difference in the project.properties file
    – Restarting netbeans may have helped resolve the “coberta.jar ant path” issue when copying the jar to the ant/lib directory
    – Only realized at the end that right clicking the Netbeans project and selecting “Test” executes the JUnit section of the ant script in build.xml/build-impl.xml

  7. Thank you very much for this tutorial! It is clean & simple to follow. I just created my first project with code coverage available! It’s great, because before i found this article i checked a lot of others and information was wrong or complex or incomplete.. This tutorial works perfectly with Netbeans 7 & JUnit 4 unit test. So thanks again!

  8. I’m trying to run the ‘test’ Ant target, but getting an error message:

    Deleting directory C:\development\MyApp\build\instrumented
    Deleting directory C:\development\MyApp\build\report\cobertura
    Created dir: C:\development\MyApp\build\instrumented
    Created dir: C:\development\MyApp\build\report\cobertura
    C:\development\MyApp\build.xml:79:
    java.lang.NoClassDefFoundError: org/apache/log4j/Logger
    at net.sourceforge.cobertura.util.CommandLineBuilder.(CommandLineBuilder.java:76)
    at net.sourceforge.cobertura.ant.InstrumentTask.execute(InstrumentTask.java:154)
    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
    at sun.reflect.GeneratedMethodAccessor101.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
    at org.apache.tools.ant.Task.perform(Task.java:348)

  9. Ok, I updated the ‘taskdef’-s ‘classpath’ attribute to include the path to the log4j JAR file, and tried again, but now I get another error message:

    Deleting directory C:\development\MyApp\build\instrumented
    Deleting directory C:\development\MyApp\build\report\cobertura
    Created dir: C:\development\MyApp\build\instrumented
    Created dir: C:\development\MyApp\build\report\cobertura
    java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor
    java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor
    Caused by: java.lang.ClassNotFoundException: org.objectweb.asm.ClassVisitor
    Caused by: java.lang.ClassNotFoundException: org.objectweb.asm.ClassVisitor
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    Could not find the main class: net.sourceforge.cobertura.instrument.Main. Program will exit.
    Could not find the main class: net.sourceforge.cobertura.instrument.Main. Program will exit.
    Exception in thread “main” Exception in thread “main”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s