关于cobertura的介绍可参考我转载的几篇文章,这里就不做介绍了.这里我想介绍一下cobertura和中间件的结合使用。
我们的项目是一个J2EE的项目,涉及了spring,hibernate,struts,EJB。部署在websphere上,本地的开发环境是IBM RAD。项目组自己开发了一个基于JUnit的测试框架,可以通过JSP调用测试类得出测试结果。美中不足的是该框架得不到代码覆盖率。于是我们决定引入cobertura.
分析cobertura自带的example的bulid.xml我们可以将其分解成几个步骤:
1.编译源代码,该步骤其实IDE已经替我们完成了,不需要通过ant去编译,所以省去.
<target name="compile" depends="init">
<javac srcdir="${src.dir}" destdir="${classes.dir}" debug="yes">
<classpath refid="cobertura.classpath" />
</javac>
</target>
2.instrument,在这里cobertura生成了instrument后的源代码。并生成cobertura.ser信息文件,该文件很重要,包含了需要被测试的类的信息。
<target name="instrument" depends="init,compile">
<!--
Remove the coverage data file and any old instrumentation.
-->
<delete file="cobertura.ser"/>
<!--<delete dir="${instrumented.dir}" />
-->
<!--
Instrument the application classes, writing the
instrumented classes into ${build.instrumented.dir}.
-->
<cobertura-instrument todir="${instrumented.dir}">
<!--
The following line causes instrument to ignore any
source line containing a reference to log4j, for the
purposes of coverage reporting.
-->
<ignore regex="org.apache.log4j.*" />
<fileset dir="${classes.dir}">
<!--
Instrument all the application classes, but
don't instrument the test classes.
-->
<include name="**/*.class" />
<exclude name="**/*Test.class" />
</fileset>
</cobertura-instrument>
</target>
3.test ,这步是生成详细代码覆盖信息的步骤,并生成JUnit的测试结果。这里需要用instrument后的*.class替代原来的*.class,当instrument后的*.class被执行时,它们会纪录被调用的信息,并写入之前生成的信息文件cobertura.ser。
<target name="test" depends="init,compile">
<junit fork="yes" dir="${basedir}" failureProperty="test.failed">
<!--
Note the classpath order: instrumented classes are before the
original (uninstrumented) classes. This is important.
-->
<classpath location="${instrumented.dir}" />
<classpath location="${classes.dir}" />
<!--
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="xml" />
<test name="${testcase}" todir="${reports.xml.dir}" if="testcase" />
<batchtest todir="${reports.xml.dir}" unless="testcase">
<fileset dir="${src.dir}">
<include name="**/*Test.java" />
</fileset>
</batchtest>
</junit>
<junitreport todir="${reports.xml.dir}">
<fileset dir="${reports.xml.dir}">
<include name="TEST-*.xml" />
</fileset>
<report format="frames" todir="${reports.html.dir}" />
</junitreport>
</target>
4.生成代码覆盖率报告。
<target name="coverage-check">
<cobertura-check branchrate="34" totallinerate="100" />
</target>
<target name="coverage-report">
<!--
Generate an XML file containing the coverage data using
the "srcdir" attribute.
-->
<cobertura-report srcdir="${src.dir}" destdir="${coverage.xml.dir}" format="xml" />
</target>
<target name="alternate-coverage-report">
<!--
Generate a series of HTML files containing the coverage
data in a user-readable form using nested source filesets.
-->
<cobertura-report destdir="${coverage.html.dir}">
<fileset dir="${src.dir}">
<include name="**/*.java"/>
</fileset>
</cobertura-report>
</target>
经过分析,这些步骤中只有第三步test部分执行有问题,因为没有websphere的环境,所以我决定将第三步分离,通过项目自带的JUnit框架来调用测试类。首先我执行instrument步骤,然后启动websphere服务器。在这里,正式服务器和RAD自带的websphere有所区别。正式的服务器需要用instrument后的*.class替换原来的,打包后重新发布。测试服务器上我采用先启动,然后替换发布后的*.class。然后我通过测试框架在jsp上执行测试类,此时,所有的信息并没有写入到相应的cobertura.ser文件中,只有当server停止时,系统才会将信息写入文件。因为在测试框架执行instrument后的class时,我们无法指定信息文件的位置,所以会在C:\RAD7\SDP70\runtimes\base_v61\profiles\serverName 文件夹下生成新的cobertura.ser文件,serverName为配置的server名称。然后再利用cobertura自带的merge功能将这两个cobertura.ser文件合并.
5.merge
<target name="merge" description="merge files">
<cobertura-merge>
<fileset dir="${basedir}">
<include name="**/cobertura1.ser"/>
<include name="**/cobertura22.ser"/>
</fileset>
</cobertura-merge>
</target>
最后,我们再通过ant生成相应的代码覆盖率的报告.这样,我们就完成了cobertura和中间件的结合.
PS:各种中间件生成cobertura.ser的位置有所不同.但都可以通过这种方式使用cobertura.