单元测试-JUnit+Ant+Cobertura生成单元测试代码覆盖率

作者:聂勇 欢迎转载,请保留作者信息并说明文章来源!
2012-外伶仃岛

上一篇文章《单元测试-使用JUnit+Ant自动化执行单元测试并生成报告》说明了JUnit+Ant自动化执行单元测试和生成报告。本篇文章继续讲解单元测试中如何生成单元测试代码覆盖率报告。

Cobertura通过额外的语句来记录在测试时类的哪些行被执行,哪些行没有执行,以HTML或XML格式生成报告。通过报告,我们可以非常容易发现我们漏掉的测试用例,从而提高代码的健壮性。Cobertura被设计成可结合Ant运行。

一、编写用Cobertura生成报告的Ant脚本

1、本次使用Cobertura的当前最新版本1.9.4.1,它依赖的类库清单如下:

1
2
3
4
5
6
<path id="cobertura.classpath">
<pathelement location="${src.extend.lib.dir}/cobertura-1.9.4.1.jar" />
<pathelement location="${play.lib.dir}/lib/asm-all-3.3.1.jar" />
<pathelement location="${play.lib.dir}/lib/log4j-1.2.16.jar" />
<pathelement location="${src.extend.lib.dir}/jakarta-oro-2.0.8.jar" />
</path>

2、首先,添加一个taskdef。然后,配置一个cover-instrument任务,用字节码技术往已经编译好的class中添加日志代码,生成用于测量代码覆盖率的class。

1
2
3
4
5
6
7
8
9
<taskdef classpathref="cobertura.classpath" resource="tasks.properties" />
<target name="cover-instrument" depends="compile">
<mkdir dir="${target.cover-test.dir}"/>
<cobertura-instrument todir="${target.cover-test.dir}">
<fileset dir="${target.java.dir}">
<include name="**/**.class" />
</fileset>
</cobertura-instrument>
</target>

<cobertura-instrument>标签配置属性说明:

  • todir - 存放织入了日志代码的测量代码覆盖率的class。

<cobertura-instrument>中的子元素<fileset>指定需要生成代码覆盖率报告的class。

3、添加一个cover-test任务,用于执行单元测试代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
<target name="cover-test" depends="cover-instrument">
<mkdir dir="${target.cover-test-report.dir}"/>
<junit printsummary="on" haltonerror="on" haltonfailure="on" fork="on">
<classpath path="${target.cover-test.dir}" />
<classpath refid="app.test.classpath" />
<classpath refid="app.classpath" />
<batchtest todir="${target.cover-test-report.dir}">
<fileset dir="${target.unit-test.dir}">
<include name="**/*Test.class" />
</fileset>
</batchtest>
</junit>
</target>

注:

  • 被织入了日志代码用于测量代码覆盖率的class必须位于所有的最前面。
  • 中的fork必须启用。可设置为”on”,”true”或”yes”。

4、定义一个cover-report任务。生成代码覆盖率报告。

1
2
3
<target name="cover-report" depends="cover-test">
<cobertura-report srcdir="${src.java.dir}" destdir="${target.cover-test-report.dir}" />
</target>

二、代码覆盖率报告样本

在命令行中执行:ant cover-report 生成代码覆盖率报告。类似如下:
代码覆盖率报告样本

附录:完整的Ant脚本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
<?xml version="1.0" encoding="UTF-8" ?>
<project name="busimonitor" basedir=".">
<property name="src.java.dir" location="${basedir}/app" />
<property name="src.test.dir" location="${basedir}/test" />
<property name="target.dir" location="${basedir}/classes" />
<property name="target.java.dir" location="${target.dir}/java" />
<property name="target.unit-test.dir" location="${target.dir}/unit-test" />
<property name="target.cover-test.dir" location="${target.dir}/cover-test" />
<property name="src.extend.lib.dir" location="${basedir}/lib"/>
<property name="play.lib.dir" location="/devdata/projects/game/play-1.2.5/framework" />
<property name="target.report.dir" location="${basedir}/report" />
<property name="target.unit-test-report.dir" location="${target.report.dir}/unit-test" />
<property name="target.cover-test-report.dir" location="${target.report.dir}/cover-test" />
<path id="app.classpath">
<fileset dir="${play.lib.dir}">
<include name="**/*.jar" />
</fileset>
<fileset dir="${src.extend.lib.dir}">
<include name="*.jar" />
</fileset>
<path location="${target.java.dir}" />
<path location="${basedir}/conf" />
</path>
<path id="app.test.classpath">
<path location="${target.unit-test.dir}" />
</path>
<target name="compile.java">
<mkdir dir="${target.java.dir}" />
<javac srcdir="${src.java.dir}" destdir="${target.java.dir}"
debug="on" source="1.6" includeantruntime="on">
<classpath refid="app.classpath"></classpath>
</javac>
</target>
<target name="compile.test" depends="compile.java">
<mkdir dir="${target.unit-test.dir}" />
<javac srcdir="${src.test.dir}" destdir="${target.unit-test.dir}"
debug="on" source="1.6" includeantruntime="on">
<classpath refid="app.classpath"></classpath>
<classpath refid="app.test.classpath"></classpath>
</javac>
<copy todir="${target.unit-test.dir}">
<fileset dir="${src.test.dir}">
<include name="**/*.properties" />
<include name="**/*.xml" />
</fileset>
</copy>
</target>
<target name="compile" depends="compile.java, compile.test"></target>
<target name="unit-test" depends="compile">
<mkdir dir="${target.unit-test-report.dir}" />
<junit printsummary="on" haltonerror="off"
haltonfailure="off" fork="on">
<formatter type="plain" usefile="off"/>
<formatter type="xml" usefile="on" />
<batchtest todir="${target.unit-test-report.dir}">
<fileset dir="${target.unit-test.dir}">
<include name="**/*Test.class"/>
</fileset>
</batchtest>
<classpath refid="app.classpath"></classpath>
<classpath refid="app.test.classpath"></classpath>
</junit>
</target>
<target name="unit-test-report" depends="unit-test">
<mkdir dir="${target.unit-test-report.dir}/html" />
<junitreport todir="${target.unit-test-report.dir}">
<fileset dir="${target.unit-test-report.dir}">
<include name="TEST-*.xml" />
</fileset>
<report todir="${target.unit-test-report.dir}/html" />
</junitreport>
</target>
<taskdef classpathref="cobertura.classpath" resource="tasks.properties" />
<target name="cover-instrument" depends="compile">
<mkdir dir="${target.cover-test.dir}"/>
<cobertura-instrument todir="${target.cover-test.dir}">
<fileset dir="${target.java.dir}">
<include name="**/**.class" />
</fileset>
</cobertura-instrument>
</target>
<target name="cover-test" depends="cover-instrument">
<mkdir dir="${target.cover-test-report.dir}"/>
<junit printsummary="on" haltonerror="on" haltonfailure="on" fork="on">
<classpath path="${target.cover-test.dir}" />
<classpath refid="app.test.classpath" />
<classpath refid="app.classpath" />
<batchtest todir="${target.cover-test-report.dir}">
<fileset dir="${target.unit-test.dir}">
<include name="**/*Test.class" />
</fileset>
</batchtest>
</junit>
</target>
<target name="cover-report" depends="cover-test">
<cobertura-report srcdir="${src.java.dir}" destdir="${target.cover-test-report.dir}" />
</target>
</project>

参考资料 | References