学习Cobertura的起因是前天晚上媳妇儿(终于有出场机会了)突然问我有没有用过一些可以统计单元测试覆盖率的工具,答曰:木有...感觉比较丢人,于是昨天晚上研究了一把,今天顺便share一下。
因为之前没有用过这方面的工具,所以只能Google一下了,发现有很多这方面的工具,看着比较顺眼的有JCoverage, EMMA, Cobertura等等,因为JCoverage收费了,所以最后挑了一个自己感觉生成的report比较好看的学习了一把:Cobertura。 (如果有更好的工具,还望不吝赐教)
刚看到Cobertura的时候,比较纠结,因为不认识这个词儿,也查不到是什么意思,据说是西班牙语的“覆盖率”之类的意思,我也无从考究了,反正现在我是老写错,囧RZ...
以上都是闲篇儿...
--- James Gosling mused: "I don't think anybody tests enough of anything."
做单元测试是developer都要接触的事情,工具也基本上都是选择JUnit或者TestNG,但是无论是JUnit还是TestNG都只能得出一个测试用例相关的报表
从这个报表中我们能得信息是,测试用例的执行情况,成功率,失败率,哪个失败了等等。通过这份报表我们并不能得悉我们是否把所有的功能代码都测试到了,那么这时候我们就需要引入单元测试覆盖率的概念了。
单元测试覆盖率通俗的讲就是多少行代码被测试用例运行到了,多少个block被执行了,多少个包被执行了等,通过这些数据我们可以清楚的了解测试的覆盖率情况,进而反向的改善已有的或者新添加测试用例去尽可能多的覆盖功能代码,block等,以提高代码的可信赖度。
对于Java而言,进行覆盖率分析的方式有三类:第一种是将instrumentation(不知道怎么翻译好,测试仪表?),直接加入到源代码中;第二种是将instrumentation加入到编译好的Java字节码中;第三种是在一个可编辑的虚拟机中运行代码。Cobertura选择了第二种方式。
为了便于使用,Cobertura提供了两种方式将Cobertura集成到已有的运行环境中: Ant和命令行
总结起来Cobertura做的事情就是:
1. Cobertura将instrumentation加入到编译好的需要被检测的Java类的字节码中。
2. 运行测试用例的时候Cobertura通过之前安插好的instrumentation统计每一行代码是否被执行,所有被植入instrumentation的类的序列化信息将被写入cobertura.ser。
3. 根据统计结果生成报表,格式为XML或者HTML。
整个过程不需要我们额外写任何Java代码,只需要通过ant脚本或者命令行触发相应的操作。
下面首先介绍一下使用ant脚本的方式。
第一步,下载最新的Cobertura,解压。下载地址为http://cobertura.sourceforge.net/download.html
第二步,将Cobertura目录下面的Cobertura.jar和lib下所有jar拷贝到你的工程的某个目录下。
第三步,创建ant脚本,或者在已有的ant脚本中添加相应的target。
现在开始设置ant脚本
第一步,将cobertura.jar以及Cobertura/lib下的所有jar引入classpath
<path id="lib.classpath">
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>
注:lib.dir是你存放cobertura.jar以及/Conbertura/lib/*.jar的地方
第二步,将cobertura自身定义的task引入到ant脚本中
<taskdef classpathref="lib.classpath" resource="tasks.properties" />
第三步,编译工程代码到某个目录,比如${src.java.classes.dir}
注:你可以选择将所有的业务代码和测试代码编译到一个classes目录下,或者选择编译到不同的目录下,在本例中将使用不同的目录存放java.src和test.src。
<target name="compile" depends="init">
<javac srcdir="${src.java.dir}" destdir="${src.java.classes.dir}" debug="yes">
<classpath refid="lib.classpath" />
</javac>
<javac srcdir="${src.test.dir}" destdir="${src.test.classes.dir}" debug="yes">
<!-- This is very import to include the src.java.classes.dir here -->
<classpath location="${src.java.classes.dir}" />
<classpath refid="lib.classpath" />
</javac>
</target>
注:src.java.dir存放所有的将被测试的java类,src.java.classes.dir存放java类的编译字节码;src.test.dir存放所有的测试用例, src.test.classes.dir存放测试用例的编译字节码。init target用来创建一些备用的目录,将包含在附件的完整工程代码中。
第四步,定义target,向生成的java.class里插入instrumentation,test.class将不插入instrumentation,因为我们不关心测试用例本身的覆盖率。
<target name="instrument">
<!-- Remove the coverage data file and any old instrumentation classes -->
<delete file="cobertura.ser" />
<delete dir="${instrumented.classes.dir}" />
<!-- Instrument the application classes, writing the instrumented classes into ${instrumented.classes.dir} -->
<cobertura-instrument todir="${instrumented.classes.dir}">
<!-- The following line causes instrument to ignore any source line containing a reference to log4j, for the purpose of coverage reporting -->
<ignore regex="org.apache.log4j.*"/>
<fileset dir="${src.java.classes.dir}">
<include name="**/*.class"/>
</fileset>
</cobertura-instrument>
</target>
注:instrumented.classes.dir存在所有被植入instrumentation的Java class。如果java代码和测试用例被编译到了同一个目录下,可以使用如<exclude name="**/*Test.class" />忽略测试用例。
第五步,执行测试用例,同时Cobertura将在后台统计代码的执行情况。这一步就是普通的junit的target,将执行所有的测试用例,并生成测试用例报表。
<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.classes.dir}" />
<classpath location="${src.java.classes.dir}" />
<classpath location="${src.test.classes.dir}" />
<classpath refid="lib.classpath" />
<formatter type="xml"/>
<test name="${testcase}" todir="${reports.junit.xml.dir}" if="testcase" />
<batchtest todir="${reports.junit.xml.dir}" unless="testcase">
<fileset dir="${src.test.dir}">
<include name="**/*.java"/>
</fileset>
</batchtest>
</junit>
<junitreport todir="${reports.junit.xml.dir}">
<fileset dir="${reports.junit.xml.dir}">
<include name="TEST-*.xml"/>
</fileset>
<report format="frames" todir="${reports.junit.html.dir}"/>
</junitreport>
</target>
注:这一步非常需要注意的是${instrumented.classes.dir}应该最先被引入classpath.
第六步,生成测试覆盖率报表。
<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.cobertura.html.dir}">
<fileset dir="${src.java.dir}">
<include name="**/*.java"/>
</fileset>
</cobertura-report>
</target>
注:因为我将Java代码和测试用例分别放在不同的包中,所以如果你的代码都放在一个包中的话,应该使用<exclude name="**/*Test.java" />剔除测试用例; coverage.cobertura.html.dir是存放report的地方。生成XML报表的方式将在完成的build.xml文件中给出。
报表如下图:
到此我们已经完成了生成测试覆盖率报表的全部工作,如果还想验证一下测试覆盖率,可以通过以下方式
<target name="coverage-check">
<cobertura-check branchrate="34" totallinerate="100" />
</target>
现在给出完成的build.xml文件,仅供参考:
<?xml version="1.0" encoding="UTF-8"?>
<project name="study-cobertura" default="coverage" basedir=".">
<description>The ant file for study-cobertuna</description>
<property name="src.java.dir" value="${basedir}/java" />
<property name="src.test.dir" value="${basedir}/test" />
<property name="build.dir" value="${basedir}/build" />
<property name="src.java.classes.dir" value="${build.dir}/src-java-classes" />
<property name="src.test.classes.dir" value="${build.dir}/src-test-classes" />
<property name="instrumented.classes.dir" value="${build.dir}/instrumented-classes" />
<property name="reports.dir" value="${basedir}/reports" />
<property name="reports.junit.xml.dir" value="${reports.dir}/junit-xml" />
<property name="reports.junit.html.dir" value="${reports.dir}/junit-html" />
<property name="coverage.cobertura.xml.dir" location="${reports.dir}/cobertura-xml"/>
<property name="coverage.cobertura.summary.dir" location="${reports.dir}/cobertura-summary-xml"/>
<property name="coverage.cobertura.html.dir" location="${reports.dir}/cobertura-html"/>
<property name="lib.dir" location="${basedir}/lib"/>
<path id="lib.classpath">
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>
<taskdef classpathref="lib.classpath" resource="tasks.properties" />
<target name="init">
<mkdir dir="${src.java.classes.dir}"/>
<mkdir dir="${src.test.classes.dir}"/>
<mkdir dir="${instrumented.classes.dir}"/>
<mkdir dir="${reports.dir}"/>
<mkdir dir="${reports.junit.html.dir}"/>
<mkdir dir="${reports.junit.xml.dir}"/>
<mkdir dir="${coverage.cobertura.xml.dir}"/>
<mkdir dir="${coverage.cobertura.summary.dir}"/>
<mkdir dir="${coverage.cobertura.html.dir}"/>
</target>
<target name="compile" depends="init">
<javac srcdir="${src.java.dir}" destdir="${src.java.classes.dir}" debug="yes">
<classpath refid="lib.classpath" />
</javac>
<javac srcdir="${src.test.dir}" destdir="${src.test.classes.dir}" debug="yes">
<!-- This is very import to include the src.java.classes.dir here -->
<classpath location="${src.java.classes.dir}" />
<classpath refid="lib.classpath" />
</javac>
</target>
<target name="instrument">
<!-- Remove the coverage data file and any old instrumentation classes -->
<delete file="cobertura.ser" />
<delete dir="${instrumented.classes.dir}" />
<!-- Instrument the application classes, writing the instrumented classes into ${instrumented.classes.dir} -->
<cobertura-instrument todir="${instrumented.classes.dir}">
<!-- The following line causes instrument to ignore any source line containing a reference to log4j, for the purpose of coverage reporting -->
<ignore regex="org.apache.log4j.*"/>
<fileset dir="${src.java.classes.dir}">
<include name="**/*.class"/>
</fileset>
</cobertura-instrument>
</target>
<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.classes.dir}" />
<classpath location="${src.java.classes.dir}" />
<classpath location="${src.test.classes.dir}" />
<classpath refid="lib.classpath" />
<formatter type="xml"/>
<test name="${testcase}" todir="${reports.junit.xml.dir}" if="testcase" />
<batchtest todir="${reports.junit.xml.dir}" unless="testcase">
<fileset dir="${src.test.dir}">
<include name="**/*.java"/>
</fileset>
</batchtest>
</junit>
<junitreport todir="${reports.junit.xml.dir}">
<fileset dir="${reports.junit.xml.dir}">
<include name="TEST-*.xml"/>
</fileset>
<report format="frames" todir="${reports.junit.html.dir}"/>
</junitreport>
</target>
<target name="coverage-check">
<cobertura-check branchrate="34" totallinerate="100" />
</target>
<!-- =================================
target: coverage-report
================================= -->
<target name="coverage-report">
<!-- Generate an XML file containing the coverage data using the 'srcdir' attribute -->
<cobertura-report srcdir="${src.java.dir}" destdir="${coverage.cobertura.xml.dir}" format="xml" />
</target>
<!-- =================================
target: summary-coverage-report
================================= -->
<target name="summary-coverage-report">
<!-- Generate an summary XML file containing the coverage data using the 'srcidir' attribute -->
<cobertura-report srcdir="${src.java.dir}" destdir="${coverage.cobertura.summary.dir}" format="summaryXml" />
</target>
<!-- =================================
target: alternate-coverage-report
================================= -->
<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.cobertura.html.dir}">
<fileset dir="${src.java.dir}">
<include name="**/*.java"/>
</fileset>
</cobertura-report>
</target>
<!-- =================================
target: clean
================================= -->
<target name="clean" description="Remove all files created by the build/test process">
<delete dir="${src.java.classes.dir}" />
<delete dir="${src.test.classes.dir}" />
<delete dir="${instrumented.classes.dir}" />
<delete dir="${reports.dir}" />
<delete file="cobertura.log" />
<delete file="cobertura.ser" />
</target>
<!-- =================================
target: coverage
================================= -->
<target name="coverage" depends="clean, compile, instrument, test, coverage-report, summary-coverage-report, alternate-coverage-report" description="Compile, instrument ourself, run the tests and generate JUnit and coverage reports." />
</project>
工程目录结构如下图:
如果还想使用命令行方式生成覆盖率报表,可以参照以下命令行生成报表
命令行方式如下:
//@rem Go to the cobertura folder
cd C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\tool\cobertura
//@rem list all java source to javalist.txt
dir C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\java\*.java/s/b > javalist.txt
//@rem list all test case source to testlist.txt
dir C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\test\*.java/s/b > testlist.txt
//@rem compile all java sources
javac -d C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\build\src-java-classes @javalist.txt
//@rem compile all test case sources
javac -classpath "$CLASSPATH;C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\lib\junit-4.8.2.jar;C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\build\src-java-classes" -d C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\build\src-test-classes @testlist.txt
//@rem instrument the java class file
cobertura-instrument.bat --destination C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\build\instrumented-classes --ignore org.apache.log4j.* --datafile ../../cobertura.ser C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\build\src-java-classes
//@rem go to the java src folder
cd C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\build\src-java-classes
//@rem run test case through JUnit4
java -cp C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\lib\junit-4.8.2.jar;C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\lib\cobertura.jar;C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\build\instrumented-classes;C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\build\src-java-classes;C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\build\src-test-classes -Dnet.sourceforge.cobertura.datafile=C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\cobertura.ser org.junit.runner.JUnitCore com.javaeye.terrencexu.cobertura.CalculatorTest
//@rem go to cobertura folder
cd C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\tool\cobertura
//@rem generate coverage report
cobertura-report.bat --format html --datafile C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\cobertura.ser --destination C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\reports\cobertura-html C:\eclipse\workspace1\Terrence-JavaStudy\study-cobertura\java
命令行模式用的比较少,不再赘述,感兴趣,可以按上述顺序执行一遍。
- 大小: 13.4 KB
- 大小: 9.7 KB
- 大小: 9.9 KB
分享到:
相关推荐
总之,Cobertura作为一款强大的测试覆盖率工具,为Java开发者提供了一种直观的方式来评估测试的质量,并且能促进更全面的单元测试实践。通过熟练使用Cobertura,开发者可以确保他们的代码被充分测试,提高软件的稳定...
4. 统计测试覆盖率,评估测试的充分性。 六、测试总结 单元测试帮助我们在早期发现并修复问题,提高了代码质量,减少了集成测试和系统测试的压力。通过本次测试,网上书店系统的各个模块表现稳定,满足预期功能。...
Cobertura 是一个用于 Java 代码覆盖率测试的工具,它能够帮助开发者测量和跟踪他们的源代码有多少被单元测试覆盖。 在描述 "cobertura-1.9.4.1-bin.zip" 中,没有额外的具体信息,但我们可以推断这可能是一个 ZIP ...
另一方面,PHPUnit 是PHP的单元测试框架,它内置了对代码覆盖率的支持。通过在测试运行时开启覆盖率收集,开发者可以直接在PHPUnit的输出中看到覆盖率数据。此外,PHPUnit还可以与不同的后处理工具(如 Clover、...
使用下面的代码片段运行测试套件,以便在终端输出中显示单元测试结果和代码覆盖率统计信息。 还将生成一些 Jenkins 友好的 XML 结果文件(用于单元测试的 JUnit 和用于代码覆盖率的 Cobertura)。 node_modules/...
Cobertura是一个开源项目,它提供了一种测量Java代码覆盖率的方式,即统计代码中被单元测试覆盖的部分。通过这个Gradle插件,开发者可以在他们的构建流程中轻松地集成Cobertura,以确保代码的质量和测试的全面性。 ...
代码覆盖率并不能代表单元测试的整体质量,但可以提供一些测试覆盖率相关的信息,可以和其他一些测试指标一起来使用。 4. 设计/开发约束 软件开发中有很多设计约束和原则,其中包括类/方法的长度、一个类中方法/...
7. **测试工具**:生成覆盖率报告通常需要使用专门的工具,如JaCoCo、Cobertura、Istanbul等,这些工具可以集成到开发流程中,自动化收集和分析覆盖率数据。 8. **质量保证**:高代码覆盖率并不代表高质量的软件,...
然而,使用JUnit、JsUnit、DBUnit等工具进行单元测试和自动化测试,结合Cobertura等统计工具进行覆盖率分析,不仅能够发现潜在问题,也有助于提升代码质量和性能。 项目经理的角色不仅是协调者,更是团队的榜样。...
- Cobertura:开源项目,用于统计单元测试对代码的覆盖率。 - SMTP(Simple Mail Transfer Protocol):简单邮件发送协议。 在进行Jenkins的环境搭建时,可以通过官网下载或者使用网盘下载的方式获取Jenkins.war包...
Coverlet是.NET生态中的一个开源代码覆盖率工具,它能够帮助开发者测量他们的单元测试覆盖了多少代码。这个项目可能是为了提供更方便的方式来处理和分析由Coverlet产生的JSON输出。 在C#开发中,测试覆盖率是非常...
9. **代码覆盖率工具**:例如JaCoCo或Cobertura,用于评估测试覆盖的代码百分比,确保测试的全面性。 10. **版本控制**:使用Git进行版本控制是现代开发的常态,了解分支策略(如GitFlow或GitHub Flow)和合并冲突...
6. **代码覆盖率工具**:JaCoCo和Cobertura提供代码覆盖率报告,帮助开发者确保测试覆盖了足够多的代码路径,从而实证地评估测试的全面性。 7. **故障注入**:通过在系统中故意引入错误,我们可以实证地测试其恢复...
Maven 中的代码覆盖率插件是通过 cobertura-maven-plugin 和 emma-maven-plugin 实现的,该插件提供了对 Java 代码的代码覆盖率检查功能,能够检测出代码中的代码覆盖率。通过该插件,开发者可以对代码进行代码覆盖...
- **Cobertura**:用于Java项目的代码覆盖率工具,帮助评估测试的充分性。 **软件度量技术:** - **自动代码分析**:利用自动化工具对代码进行静态分析,检测潜在的问题。 - **持续集成/持续部署(CI/CD)**:确保...