More‎ > ‎

How to Run Findbugs, Pmd, Checkstyle, JUnit and Cobertrua with an Ant Build-Script?



This article describes an Ant-build sample that runs the five tools Findbugs [1], Checkstyle [2], PMD [3], JUnit [4] and Cobertura [5]. Additionally it creates and collects the native HTML reports of each tool. Ant-builds have the big advantage over Maven-builds that you have everything under control and a minimal foot print of the build result. This justifies the overhead of writing the build.xml file. 

The sometimes huge number of not needed libraries and difficult control of the used libraries is the main reason why I don't like Maven for real projects. Maven is better than Ant [7] for quick hacks. 

More About Static Code Analysis

The Example Code

Just copy the build.xml (file #1) in your project and change the paths checkstyle.home.dir, cobertura.home.dir, findbugs.home.dir and pmd.home.dir to your directories. This example has been compiled and executed with junit-4.5.jar - but other versions should make no problem.

File #1: build.xml

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
<project name="AntDefault" default="run" basedir=".">
    <description>   
        Ant build sample for running 
        - findbugs, 
        - pmd, 
        - checkstyle, 
        - cobertrua and 
        - junit.
    </description>

     <!-- Change the paths to your individual installation directories -->
    <property name="checkstyle.home.dir" location="C:/EU/checkstyle/checkstyle-5.0" />
    <property name="cobertura.home.dir" value="C:/EU/cobertrua/cobertura-1.9.2" />
    <property name="findbugs.home.dir" value="C:/EU//findbugs/findbugs-1.3.9-rc2" />
    <property name="pmd.home.dir" value="C:/EU//pmd/pmd-4.2.5" />
    <property name="lib.dir" location="${basedir}/lib" />
    <property name="src.dir" location="${basedir}/src" />
    <property name="bin.dir" location="${basedir}/bin" />
    <property name="htm.dir" location="${basedir}/html" />
    <property name="report.dir" location="${basedir}/report" />

    <property name="report.checkstyle.dir" location="${report.dir}/checkstyle" />
    <property name="report.junit.dir" location="${report.dir}/junit" />
    <property name="report.findbugs.dir" location="${report.dir}/findbugs" />
    <property name="report.cobertura.dir" location="${report.dir}/cobertura" />
    <property name="report.pmd.dir" location="${report.dir}/pmd" />
   
    <property name="instrumented.dir" location="${basedir}/instrumented" />
    <property name="report.temp.dir" location="${report.dir}/temp" />
    <property name="cobertura.ser.file" location="${report.temp.dir}/cobertura.ser" />

    <path id="run.classpath">
        <pathelement path="${bin.dir}" />
        <pathelement path="${basedir}/lib/junit-4.5.jar" />
    </path>

    <path id="cobertura.classpath">
        <path refid="run.classpath" />
        <fileset dir="${cobertura.home.dir}">
            <include name="cobertura.jar" />
            <include name="lib/**/*.jar" />
        </fileset>
    </path>
    <taskdef classpathref="cobertura.classpath" resource="tasks.properties" />

    <!-- -->
    <target name="clean" description="Delete all result to start with a clean build.">
        <delete dir="${report.junit.dir}" />
        <delete dir="${report.findbugs.dir}" />
        <delete dir="${report.cobertura.dir}" />
        <delete dir="${report.checkstyles.dir}" />
        <delete dir="${report.temp.dir}" />
        <delete dir="${bin.dir}" />
    </target>

    <target name="prepare.report.dir" description="Prepares the reports folder">
        <copy todir="${report.dir}">
            <fileset dir="${htm.dir}">
                <include name="*.htm" />
            </fileset>
        </copy>
    </target>

    <!-- -->
    <target name="findbugs"
            depends="compile"
            description="Run code analysis over code to check for problems."
    >
        <!-- Fail this target if FindBugs is not installed. -->
        <available file="${findbugs.home.dir}/lib/findbugs.jar" property="findbugs.available" />
        <fail unless="findbugs.available"
              message="Error: FINDBUGS_HOME not set or findbugs.jar not found."
        />
        <taskdef name="findbugs"
                 classname="edu.umd.cs.findbugs.anttask.FindBugsTask"
                 classpath="${findbugs.home.dir}/lib/findbugs-ant.jar"
        />

        <!-- Run FindBugs. -->
        <mkdir dir="${report.findbugs.dir}" />
        <findbugs home="${findbugs.home.dir}"
                  workHard="true"
                  output="xml:withMessages"
                  outputFile="${report.findbugs.dir}/findbugs.xml"
        >
            <class location="${bin.dir}" />
            <auxClasspath>
                <fileset file="${basedir}/lib/junit-4.5.jar" />
            </auxClasspath>
        </findbugs>
    </target>

    <!-- -->
    <path id="pmd2.classpath">
        <pathelement location="${build}" />
        <fileset dir="${pmd.home.dir}/lib/">
            <include name="*.jar" />
        </fileset>
    </path>
    <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask" 
        classpathref="pmd2.classpath" />
    <target name="report.pmd">
        <mkdir dir="${report.pmd.dir}" />
        <pmd rulesetfiles="rulesets/favorites.xml">
            <formatter type="xml" toFile="${report.pmd.dir}/pmd_report.xml" />
            <fileset dir="${src.dir}">
                <include name="**/*.java" />
            </fileset>
        </pmd>
        <xslt in="${report.pmd.dir}/pmd_report.xml"
              style="${pmd.home.dir}/etc/xslt/pmd-report-per-class.xslt"
              out="${report.pmd.dir}/pmd_report.html"
        />
    </target>

    <!-- -->
    <target name="compile" depends="clean" description="Compile the entire project.">
        <mkdir dir="${bin.dir}" />
        <javac debug="true"
               debuglevel="lines, source"
               srcdir="${src.dir}"
               destdir="${bin.dir}"
               classpathref="run.classpath"
        />
    </target>

    <!-- -->
    <target name="cobertura.instrument"
            depends="clean, compile"
            description="Instrument the project for code coverage."
    >
        <mkdir dir="${report.temp.dir}" />
        <cobertura-instrument todir="${instrumented.dir}" datafile="${cobertura.ser.file}">
            <ignore regex="org.apache.log4j.*" />
            <fileset dir="${bin.dir}">
                <include name="**/*.class" />
                <exclude name="**/*Test.class" />
            </fileset>
        </cobertura-instrument>
    </target>

    <!-- -->
    <target name="junit"
            depends="clean, compile, cobertura.instrument"
            description="Run all junit test cases."
    >
        <mkdir dir="${report.cobertura.dir}" />
        <mkdir dir="${report.temp.dir}" />

        <junit printsummary="yes" fork="yes" haltonfailure="no">

            <!-- Specify the name of the coverage data file to use.
                 The value specified below is the default.    -->
            <sysproperty key="net.sourceforge.cobertura.datafile" 
                file="${cobertura.ser.file}" />

            <!-- Note the classpath order: instrumented classes are before 
                 the original (uninstrumented) classes.  This is important. -->
            <classpath location="${instrumented.dir}" />
            <classpath location="${bin.dir}" />
            <classpath location="${basedir}/lib/junit-4.5.jar}" />

            <!-- The instrumented classes reference classes used by the
                 Cobertura runtime, so Cobertura and its dependencies
                 must be on your classpath. -->
            <classpath refid="cobertura.classpath" />

            <formatter type="plain" />
            <formatter type="xml" />

            <batchtest todir="${report.temp.dir}">
                <fileset dir="${src.dir}">
                    <include name="**/*Test.java" />
                </fileset>
            </batchtest>
        </junit>
    </target>

    <!-- -->
    <target name="report.junit" depends="junit" 
        description="Create a report for the test result.">
        <delete dir="${report.junit.dir}" />
        <mkdir dir="${report.junit.dir}" />
        <junitreport todir="${report.junit.dir}">
            <fileset dir="${report.temp.dir}">
                <include name="*.xml" />
            </fileset>
            <report format="frames" todir="${report.junit.dir}" />
        </junitreport>
    </target>

    <!-- -->
    <target name="report.findbugs" description="Generate a report on error analysis.">
        <xslt in="${report.findbugs.dir}/findbugs.xml"
              style="${findbugs.home.dir}/src/xsl/fancy.xsl"
              out="${report.findbugs.dir}/findbugs-default.html"
        />
    </target>

    <!-- -->
    <target name="report.cobertura"
            depends="junit"
            description="Generate an HTML report on Cobertura."
    >
        <cobertura-report format="html"
                          datafile="${cobertura.ser.file}"
                          destdir="${report.cobertura.dir}"
        >
            <fileset dir="${src.dir}">
                <include name="**/*.java" />
            </fileset>
        </cobertura-report>
    </target>


    <!-- -->
    <target name="report.checkstyle" 
        description="Generate a report of code convention violations.">
        <taskdef resource="checkstyletask.properties"
                 classpath="${checkstyle.home.dir}/checkstyle-all-5.0.jar"
        />

        <!-- run verification of installation-->
        <available file="${checkstyle.home.dir}/checkstyle-all-5.0.jar"
                   property="checkstyle.available"
        />
        <fail unless="checkstyle.available"
              message="Error: CHECKSTYLE_HOME not set or checkstyle-all-5.0.jar not found."
        />
        <mkdir dir="${report.checkstyle.dir}" />

        <!-- run analysis-->
        <checkstyle config="${checkstyle.home.dir}/sun_checks.xml"
                    failureProperty="checkstyle.failure"
                    failOnViolation="false"
        >
            <formatter type="xml" tofile="${report.checkstyle.dir}/checkstyle_report.xml" />
            <fileset dir="${src.dir}" includes="**/*.java" />
        </checkstyle>

        <style in="${report.checkstyle.dir}/checkstyle_report.xml"
               out="${report.checkstyle.dir}/checkstyle_report.html"
               style="${checkstyle.home.dir}/contrib/checkstyle-noframes.xsl"
        />
    </target>

    <!-- -->
    <target name="clean.temp" description="Delete all temporary files and folders.">
        <delete dir="${instrumented.dir}" />
        <delete dir="${report.temp.dir}" />
    </target>

    <!-- -->
    <target name="run"
            description="Run the build"
            depends="clean, 
                prepare.report.dir, 
                report.checkstyle, 
                report.pmd, 
                compile,  
                cobertura.instrument, 
                junit, 
                report.junit, 
                findbugs, 
                report.findbugs, 
                report.cobertura, 
                clean.temp"
    >
    </target>

</project>

The build file expects to further files index.htm (File #2) and menue.htm (File #3) in the sub-directory "${basedir}/html". These two files create the entry page shown in figure 1.

File #2: index.htm

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN">
<html>

<head>
    <title>AntDefault Project Report</title>
    <meta name="description" content="Beschreibung eintragen">
    <meta name="keywords" 
          content="Keywords eintragen, Keyword, Keyword, Keyword, Keyword, Keyword">
    <meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
    <meta name="author" content="Markus Sprunck">
    <meta name="Content-Language" content="de">
</head>


<frameset framespacing="0" frameborder="no" border="0" >
   <frameset framespacing="10" frameborder="yes" border="2" cols="100,*">
       <frame name="nav" marginheight="0" marginwidth="0" src="menue.htm">
       <frame name="anzeige" marginheight="0" marginwidth="0" src="cobertura\index.html">
   </frameset>
</frameset>

</html>

File #3: menue.htm

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>

<style type="text/css">
<!--

body {
    font-family: Arial,sans-serif;
    font-size:12px;
    color: #F00800;
    background-color:#EFEFEF;
    margin:0px;
    padding:0px;
}

td {
    font-family: Arial,sans-serif;
    font-size:12px;
    color: #0A0000;
}

h2 {
    font-family: Arial,sans-serif;
    font-size:12px;
    color: #5F5F5F;
}


#sub a {
   display:block;
   color:#5F5F5F;
   text-decoration:none ;
   font-family:Arial,Helvetica,sans-serif;
   font-size: 13px;
   width:100px;
   background-color:#EFEFEF;
   border-bottom:solid 1px #5F5F5F;
   padding: 3px 0px 3px 8px;
}

#sub a:visited{
   color:#5F5F5F;
   text-decoration:none;
   font-family:Arial,Helvetica,sans-serif;
   font-size: 13px;
   width:100px;
   background-color:#EFEFEF;
   border-bottom:solid 1px #5F5F5F;
   padding: 3px 0px 3px 8px;
}


#sub a:hover {
   color: #000000;
   text-decoration:none ;
   font-family:Arial,Helvetica,sans-serif;
   font-size: 13px;
   width:100px;
   background-color:#FFFFFF;
   border-bottom:solid 1px #000000;
}

-->
</style>


</head>

<body vlink="#000000" alink="#FFFFFF" link="#000000" text="#000000" id="sub">

<table border="0" cellspacing="0" cellpadding="0" width="100%" height="100%">
<tr><td valign="top">
<div id="sub">
    <a target="anzeige" href="checkstyle\checkstyle_report.html">checkstyle</a>
    <a target="anzeige" href="cobertura\index.html">cobertrua</a>
    <a target="anzeige" href="findbugs\findbugs-default.html">findbugs</a>
    <a target="anzeige" href="junit\index.html">junit</a>
    <a target="anzeige" href="pmd\pmd_report.html">pmd</a>
</div>

</td></tr>
</table>

</body>
</html>

If the build is successful in the output in the console will look similar like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
Buildfile: C:\Projects\.eclipse3.7.rcp\default_ant\build.xml

clean:   [delete] Deleting directory C:\Projects\.eclipse3.7.rcp\default_ant\report\junit
   [delete] Deleting directory C:\Projects\.eclipse3.7.rcp\default_ant\report\findbugs
   [delete] Deleting directory C:\Projects\.eclipse3.7.rcp\default_ant\report\cobertura
   [delete] Deleting directory C:\Projects\.eclipse3.7.rcp\default_ant\bin

prepare.report.dir:

report.checkstyle:

[checkstyle] Running Checkstyle 5.0 on 7 files
    [style] Warning: the task name <style> is deprecated. Use <xslt> instead.
    [style] Processing C:\Projects\.eclipse3.7.rcp\default_ant\report\checkstyle\
            checkstyle_report.xml to 
            C:\Projects\.eclipse3.7.rcp\default_ant\report\checkstyle\checkstyle_report.html
    [style] Loading stylesheet C:\EU\checkstyle\checkstyle-5.0\contrib\checkstyle-noframes.xsl

report.pmd:
     [xslt] Processing C:\Projects\.eclipse3.7.rcp\default_ant\report\pmd\pmd_report.xml to 
            C:\Projects\.eclipse3.7.rcp\default_ant\report\pmd\pmd_report.html
     [xslt] Loading stylesheet C:\EU\pmd\pmd-4.2.5\etc\xslt\pmd-report-per-class.xslt

compile:
    [mkdir] Created dir: C:\Projects\.eclipse3.7.rcp\default_ant\bin
    [javac] C:\Projects\.eclipse3.7.rcp\default_ant\build.xml:120: warning: 'includeantruntime' 
            was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
    [javac] Compiling 7 source files to C:\Projects\.eclipse3.7.rcp\default_ant\bin
    [javac] Creating empty C:\Projects\.eclipse3.7.rcp\default_ant\bin\com\sprunck\tests\
            package-info.class
    [javac] Creating empty C:\Projects\.eclipse3.7.rcp\default_ant\bin\com\sprunck\bee\
            package-info.class
    [javac] Creating empty C:\Projects\.eclipse3.7.rcp\default_ant\bin\com\sprunck\foo\
            package-info.class

cobertura.instrument:
    [mkdir] Created dir: C:\Projects\.eclipse3.7.rcp\default_ant\report\temp
[cobertura-instrument] Cobertura 1.9.2 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
[cobertura-instrument] Instrumenting 5 files to C:\Projects\.eclipse3.7.rcp\default_ant\instrumented
[cobertura-instrument] Cobertura: Saved information on 5 classes.
[cobertura-instrument] Instrument time: 109ms

junit:
    [mkdir] Created dir: C:\Projects\.eclipse3.7.rcp\default_ant\report\cobertura
    [junit] Running com.sw_engineering_candies.BeeTest
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0,094 sec
    [junit] Cobertura: Loaded information on 5 classes.
    [junit] Cobertura: Saved information on 5 classes.
    [junit] Running com.sw_engineering_candies.tests.FooTest
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0,094 sec
    [junit] Cobertura: Loaded information on 5 classes.
    [junit] Cobertura: Saved information on 5 classes.

report.junit:
    [mkdir] Created dir: C:\Projects\.eclipse3.7.rcp\default_ant\report\junit
[junitreport] Processing C:\Projects\.eclipse3.7.rcp\default_ant\report\junit\
        TESTS-TestSuites.xml to 
        c:\temp\null1611982524
[junitreport] Loading stylesheet jar:file:/C:/EU/eclipse.3.7/plugins/
        org.apache.ant_1.8.2.v20110505-1300/
        lib/ant-junit.jar!/org/apache/tools/ant/taskdefs/optional/junit/xsl/junit-frames.xsl
[junitreport] Transform time: 293ms
[junitreport] Deleting: c:\temp\null1611982524

findbugs:
 [mkdir] Created dir: C:\Projects\.eclipse3.7.rcp\default_ant\report\findbugs
 [findbugs] Executing findbugs from ant task
 [findbugs] Running FindBugs...
 [findbugs] Warnings generated: 4
 [findbugs] Calculating exit code...
 [findbugs] Setting 'bugs found' flag (1)
 [findbugs] Exit code set to: 1
 [findbugs] Java Result: 1
 [findbugs] Output saved to C:\Projects\.eclipse3.7.rcp\default_ant\report\findbugs/findbugs.xml

report.findbugs:
     [xslt] Processing C:\Projects\.eclipse3.7.rcp\default_ant\report\findbugs\findbugs.xml to 
            C:\Projects\.eclipse3.7.rcp\default_ant\report\findbugs\findbugs-default.html
     [xslt] Loading stylesheet C:\EU\findbugs\findbugs-1.3.9-rc2\src\xsl\fancy.xsl

report.cobertura:
[cobertura-report] Cobertura 1.9.2 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
[cobertura-report] Cobertura: Loaded information on 5 classes.
[cobertura-report] Report time: 402ms

clean.temp:
   [delete] Deleting directory C:\Projects\.eclipse3.7.rcp\default_ant\instrumented
   [delete] Deleting directory C:\Projects\.eclipse3.7.rcp\default_ant\report\temp

run:
BUILD SUCCESSFUL
Total time: 11 seconds

Open file index.htm and you should see something like this:

Figure 1: Sample report with Cobertura view

Recommendation

  • The Ant-build and results of static and dynamic code analysis can also easily be managed and visualized with Hudson [6]. This is my personal approach to manage small and intermediate projects.

References

[1]  FindBugs - Is a static code analysis tool that analyses Java byte code and detects a wide range of problems.
[2]  Checkstyle - Is a development tool to help programmers write Java code that adheres to a coding standard.
[3]  PMD - Scans source code and looks for potential problems possible bugs, unused and sub-optimal code and over-complicated expressions; 
[4]  JUnit - Is a unit testing framework for the Java programming language.
[5]  Cobertura - Is a Java code coverage analysis tool. You can use it to determine what percentage of your source code is exercised by your unit tests.
[6] Hudson - Is an extensible Continuous Integration Server.
[7]  Apache Ant - Is a Java library and command-line tool whose mission is to drive processes described in build files as targets and extension points dependent upon each other.

Sponsored Link