Code Coverage of Unittests
Code coverage measures how many classes, methods, blocks and lines of code was used during executing unitttests. Thanks to Ant's extension support code coverage can be measured in NetBeans IDE.Tutorial how to use this feature
Create a simple J2SE project. A main class was created in the project.
Add few lines to main
method of the Main class.
package testapp; public class Main { /** * @param args the command line arguments */ public static void main(String[] args) { // TODO code application logic here if (true) { System.out.println("true"); } else { System.out.println("false"); } } |
Create a simple UnitTest in Test packages folder.
package testapp; import junit.framework.*; public class MainTest extends TestCase { public MainTest(String testName) { super(testName); } void testMain() { Main.main(null); } } |
Add Emma code coverage feature: Click to Tools|Ant's Feature in main menu. The Ant's Feature dialog is shown. Click to Add Feature button in the dialog. Add Ant's features dialog is be shown.

If Emma libraries are not installed in the IDE the downloading dialog will be shown. After successfull installation Emma Code Coverage panel is shown.

If you click to Run Tests button the tests will be run in emma. To show the code coverage report click to Show Results button.
Detail about Implementation
To add ant extension is very simply. This part is motivation and how to create your own extension. The code of
Emma ant feature was moved to xdsuite/ExperimantalTemplates
. Contribution to this module will be apreciated.
Part of layer.xml
<folder name="velocity"> <folder name="customizers"> <file name="sf-netbeans-nbxdoclet-experimentaltemplates-EmmaCustomizer.instance" /> </folder> <folder name="templates"> <file name="emmaBuild.vm" url="emmaBuild.vm"/> </folder> <folder name="build"> <file name="EmmaBuild.xml" url="emmaBuild.xml"/> </folder> </folder> |
EmmaBuild.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- Code coverage ant extension --> <featuredefs> <featuredef name="Emma-codeCoverage" customizerClassRef="sf-netbeans-nbxdoclet-experimentaltemplates-EmmaCustomizer.instance" > <title>Emma Code Coverage</title> <velocityTemplate vmFile="emmaBuild.vm"/> <classpath name="emma"> <library name="emma-2.0.jar" repository="default"/> <library name="emma_ant-2.0.jar" repository="default"/> </classpath> </featuredef> </featuredefs> |
Part code of Emma Customizer
private void clearResultsButtonActionPerformed(java.awt.event.ActionEvent evt) { feature.getBuildScript().executeTarget("emma-clean", null); } private void showResultsButtonActionPerformed(java.awt.event.ActionEvent evt) { try { FileObject fo = feature.getBuildScript().getProjectFile().getFileObject("build/coverage/coverage.html"); if (fo != null) { HtmlBrowser.URLDisplayer.getDefault ().showURL (fo.getURL ()); } } catch (FileStateInvalidException e) { } } private void runCoverageButtonActionPerformed(java.awt.event.ActionEvent evt) { feature.getBuildScript().executeTarget("emma-report", null); } public Feature getFeature() { return feature; } public String save() { // no persistent data return null; } public void setFeature(Feature feature) { this.feature = feature; } |
EmmaBuild.vm template
<folder name="velocity"> <folder name="customizers"> <file name="sf-netbeans-nbxdoclet-experimentaltemplates-EmmaCustomizer.instance" /> </folder> <folder name="templates"> <file name="emmaBuild.vm" url="emmaBuild.vm"/> </folder> <folder name="build"> <file name="EmmaBuild.xml" url="emmaBuild.xml"/> </folder> </folder> <target name="emma-init" depends="project-extension-init,compile" > <property name="emma.out.dir" value="${build.dir}/out" /> <mkdir dir="${emma.out.dir}" /> <!-- output directory used for EMMA coverage reports: --> <property name="emma.coverage.dir" value="${basedir}/${build.dir}/coverage" /> <mkdir dir="${emma.coverage.dir}" /> <!-- directory that contains emma.jar and emma_ant.jar: --> <!-- path element used by EMMA taskdef below: --> <path id="emma.lib" > <path path="${emma.classpath}"/> </path> <!-- this loads <emma> and <emmajava> custom tasks: --> <taskdef resource="emma_ant.properties" classpathref="emma.lib" /> <path id="run.classpath" > <pathelement location="${build.classes.dir}" /> </path> <property name="emma.enabled" value="true" /> <!-- EMMA instr class output directory (it is important to create this property only when EMMA is enabled: --> <property name="out.instr.dir" value="${basedir}/${build.dir}/outinstr" /> <mkdir dir="${out.instr.dir}" /> <property name="emma.filter" value="" /> </target> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!-- EMMA ANT tasks are implemented as pseudo-nested tasks: <emma> container task can contain an arbitrary sequence of <instr>, <report>, and <merge>. Both the container tag and each of the nested elements support an optional boolean 'enabled' attribute: setting it to 'false' will no-op the element. This is convenient for sandwhiching normal build tasks between EMMA tasks such that coverage instrumentation and reporting could be enabled on demand. --> <target name="emma-instrument" depends="init, compile,emma-init" description="runs the examples" > <!-- Note that EMMA takes regular ANT path elements as instrumentation input, which is exceedingly convenient: --> <echo message="build.classes.dir = ${build.classes.dir}"/> <echo message="out.instr.dir = ${out.instr.dir}"/> <emma enabled="${emma.enabled}" > <instr instrpath="${build.classes.dir}" destdir="${out.instr.dir}" metadatafile="${emma.coverage.dir}/metadata.emma" merge="true" > <!-- note that coverage filters can be set through nested <filter> elements as well: many of EMMA setting are 'mergeable' in the sense that they can be specified multiple times and the result is a union of all such values. Here we are not merging several filters together but merely demonstrating that it is possible: --> <filter value="${emma.filter}" /> </instr> </emma> </target> <!-- run Main. In v2.0, EMMA coverage data is dumped on JVM exit. For this to happen the JVM must be forked: --> <target name="emma-run" depends="init,compile-test,emma-init,emma-instrument,compile-test,-pre-test-run"> <junit showoutput="true" fork="true" dir="${basedir}" failureproperty="tests.failed" errorproperty="tests.failed"> <batchtest todir="${build.test.results.dir}"> <fileset dir="${test.src.dir}" /> </batchtest> <classpath> <path location="${out.instr.dir}"/> <path path="${run.test.classpath}"/> <path path="${emma.classpath}"/> </classpath> <syspropertyset> <propertyref prefix="test-sys-prop."/> <mapper type="glob" from="test-sys-prop.*" to="*"/> </syspropertyset> <formatter type="brief" usefile="false"/> <formatter type="xml"/> <jvmarg value="-Demma.coverage.out.file=${emma.coverage.dir}/coverage.emma" /> <jvmarg value="-Demma.coverage.out.merge=false" /> </junit> </target> <target name="emma-report" if="have.tests" depends="emma-run"> <!-- if enabled, generate coverage report(s): --> <emma enabled="${emma.enabled}" > <report sourcepath="${src.dir}" sort="+block,+name,+method,+class" metrics="method:70,block:80,line:80,class:100" > <!-- 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="${emma.coverage.dir}" > <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: --> <txt outfile="${emma.coverage.dir}/coverage.txt" depth="package" columns="class,method,block,line,name" /> <xml outfile="${emma.coverage.dir}/coverage.xml" depth="package" /> <html outfile="${emma.coverage.dir}/coverage.html" depth="method" columns="name,class,method,block,line" /> </report> </emma> </target> <target name="emma-clean" > </target> |