这两天想做些实验,研究了半天Cobertura,发现还是不能满足我的需求。不过也借此机会总结一下Ant+JUnit+Cobertura执行测试用例的经验。主要是参考了下面两篇文章:
http://aofengblog.blog.163.com/blog/static/6317021201312763630878/
http://www.ibm.com/developerworks/cn/java/j-cobertura/
其实这两篇文章已经说得很清楚了,我再把一些细节总结一下(以Apache POI自带的测试用例为例):
在这里:http://cobertura.github.io/cobertura/,有Cobertura的最新下载链接,下载并解压后,将cobertura-2.0.3.jar和lib里的所有JAR包,可以放到一个新的文件夹中,例如:cobertura-lib,而后,在build.xml把这些JAR包包含进来:
<path id="cobertura.classpath">
<fileset dir="cobertura-lib">
<include name="*.jar"/>
</fileset>
</path>
而后定义一些property,这些可以因人而异,我这里列出来是为后面叙述方便:
<property name="target.cover-test.dir" location="${main.output.dir}/cover-test" />
<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" />
要使用cobertura,其实也就分三步:1.用cobertura插桩(instrument),2.执行经过插桩的代码,3.生成报告。所以下面从这三个步骤介绍:
首先进行插桩(其实cobertura也是基于ASM进行插桩的):
<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="${main.output.dir}">
<include name="**/**.class" />
</fileset>
</cobertura-instrument>
</target>
taskdef这行,是Ant使用第三方任务的方法,如果第三方提供自己的任务,都会事先写好properties供他人使用。该properties文件一般存在jar包中。如果我们将cobertura-2.0.3.jar解压,就可以看到tasks.properties这样一个文件:
cobertura-instrument=net.sourceforge.cobertura.ant.InstrumentTask
cobertura-merge=net.sourceforge.cobertura.ant.MergeTask
cobertura-report=net.sourceforge.cobertura.ant.ReportTask
cobertura-check=net.sourceforge.cobertura.ant.CheckTask
其含义也很简单。cover-instrument这个Target的目的就是将class文件进行二次编译,插入一些ASM的监控代码。
然后执行测试用例(这里我都是以Apache POI为例进行说明的,所以里面可能有些Project Specific的配置):
<target name="cover-test" depends="cover-instrument">
<mkdir dir="${target.cover-test-report.dir}"/>
<junit printsummary="on" haltοnerrοr="off" haltonfailure="off" fork="on">
<classpath location="cobertura-lib/cobertura-2.0.3.jar"/>
<classpath path="${target.cover-test.dir}" />
<classpath refid="test.classpath"/>
<formatter type="plain"/>
<syspropertyset refid="junit.properties"/>
<jvmarg value="${poi.test.locale}"/>
<batchtest todir="${main.reports.test}">
<fileset dir="${main.src.test}">
<include name="**/${testpattern}.java"/>
<exclude name="**/All*Tests.java"/>
<exclude name="**/TestUnfixedBugs.java"/>
<exclude name="**/TestcaseRecordInputStream.java"/>
</fileset>
</batchtest>
</junit>
</target>
需要注意的问题包括:这里需要显式地把cobertura的jar包包含进来,另外,需要将插桩以后的class文件放到classpath的开头处,其他和正常执行junit一样。
最后,生成覆盖率报告:
<target name="cover-report" depends="cover-test">
<cobertura-report srcdir="${main.src}" destdir="${target.cover-test-report.dir}" />
</target>
需要注意的是,srcdir指定的是源代码文件夹。
就简单总结这么多。