http://www.ibm.com/developerworks/cn/java/j-cobertura/
尽管测试先行编程(test-first programming)和单元测试已不能算是新概念,但测试驱动的开发仍然是过去 10 年中最重要的编程创新。最好的一些编程人员在过去半个世纪中一直在使用这些技术,不过,只是在最近几年,这些技术才被广泛地视为在时间及成本预算内开发健壮的无缺陷软件的关键所在。但是,测试驱动的开发不能超过测试所能达到的程度。测试改进了代码质量,但这也只是针对实际测试到的那部分代码而言的。您需要有一个工具告诉您程序的哪些部分没有测试到,这样就可以针对这些部分编写测试代码并找出更多 bug。
Mark Doliner 的 Cobertura (cobertura 在西班牙语是覆盖的意思)是完成这项任务的一个免费 GPL 工具。Cobertura 通过用额外的语句记录在执行测试包时,哪些行被测试到、哪些行没有被测试到,通过这种方式来度量字节码,以便对测试进行监视。然后它生成一个 HTML 或者 XML 格式的报告,指出代码中的哪些包、哪些类、哪些方法和哪些行没有测试到。可以针对这些特定的区域编写更多的测试代码,以发现所有隐藏的 bug。
阅读 Cobertura 输出
我们首先查看生成的 Cobertura 输出。图 1 显示了对 Jaxen 测试包运行 Cobertura 生成的报告。从该报告中,可以看到从很好(在 org.jaxen.expr.iter
包中几乎是 100%)到极差(在 org.jaxen.dom.html
中完全没有覆盖)的覆盖率结果。
图 1. Jaxen 的包级别覆盖率统计数据 Cobertura 通过被测试的行数和被测试的分支数来计算覆盖率。第一次测试时,两种测试方法之间的差别并不是很重要。Cobertura 还为类计算平均 McCabe 复杂度(请参阅 参考资料)。
可以深入挖掘 HTML 报告,了解特定包或者类的覆盖率。图 2 显示了 org.jaxen.function
包的覆盖率统计。在这个包中,覆盖率的范围从 SumFunction
类的 100% 到 IdFunction
类的仅为 5%。
图 2. org.jaxen.function 包中的代码覆盖率 进一步深入到单独的类中,具体查看哪一行代码没有测试到。图 3 显示了 NameFunction
类中的部分覆盖率。最左边一栏显示行号。后一栏显示了执行测试时这一行被执行的次数。可以看出,第 112 行被执行了 100 次,第 114 行被执行了 28 次。用红色突出显示的那些行则根本没有测试到。这个报告表明,虽然从总体上说该方法被测试到了,但实际上还有许多分支没有测试到。
图 3. NameFunction 类中的代码覆盖率
确认遗漏的测试
利用 Cobertura 报告,可以找出代码中未测试的部分并针对它们编写测试。例如,图 3 显示 Jaxen 需要进行一些测试,运用 name()
函数对文字节点、注释节点、处理指令节点、属性节点和名称空间节点进行测试。
如果有许多未覆盖的代码,像 Cobertura 在这里报告的那样,那么添加所有缺少的测试将会非常耗时,但也是值得的。不一定要一次完成它。您可以从被测试的最少的代码开始,比如那些所有没有覆盖的包。在测试所有的包之后,就可以对每一个显示为没有覆盖的类编写一些测试代码。对所有类进行专门测试后,还要为所有未覆盖的方法编写测试代码。在测试所有方法之后,就可以开始分析对未测试的语句进行测试的必要性。
(几乎)不留下任何未测试的代码
是否有一些可以测试但不应测试的内容?这取决于您问的是谁。在 JUnit FAQ 中,J. B. Rainsberger 写到“一般的看法是:如果 自身 不会出问题,那么它会因为太简单而不会出问题。第一个例子是 getX()
方法。假定 getX()
方法只提供某一实例变量的值。在这种情况下,除非编译器或者解释器出了问题,否则 getX()
是不会出问题的。因此,不用测试 getX()
,测试它不会带来任何好处。对于setX()
方法来说也是如此,不过,如果 setX()
方法确实要进行任何参数验证,或者说确实有副作用,那么还是有必要对其进行测试。”
我不同意。我已经记不清在“简单得不会出问题”的代码中发现的 bug 的数量了。确实,一些 getter 和 setter 很简单,不可能出问题。但是我从来就没有办法区分哪些方法是真的简单得不会出错,哪些方法只是看上去如此。编写覆盖像 setter 和 getter 这样简单方法的测试代码并不难。为此所花的少量时间会因为在这些方法中发现未曾预料到的 bug 而得到补偿。
一般来说,开始测量后,达到 90% 的测试覆盖率是很容易的。将覆盖率提高到 95% 或者更高就需要动一下脑筋。例如,可能需要装载不同版本的支持库,以测试没有在所有版本的库中出现的 bug。或者需要重新构建代码,以便测试通常执行不到的部分代码。可以对类进行扩展,让它们的受保护方法变为公共方法,这样就可以对这些方法进行测试。这些技巧看起来像是多此一举,但是它们曾帮助我在一半的时间内发现更多的未发现的 bug。
并不总是可以得到完美的、100% 的代码覆盖率。有时您会发现,不管对代码如何改造,仍然有一些行、方法、甚至是整个类是测试不到的。下面是您可能会遇到的挑战的一些例子:
- 只在特定平台上执行的代码。例如,在一个设计良好的 GUI 应用程序中,添加一个 Exit 菜单项的代码可以在 Windows PC 上运行,但它不能在 Mac 机上运行。
- 捕获不会发生的异常的
catch
语句,比如在从 ByteArrayInputStream
进行读取操作时抛出的 IOException
。
- 非公共类中的一些方法,它们永远也不会被实际调用,只是为了满足某个接口契约而必须实现。
- 处理虚拟机 bug 的代码块,比如说,不能识别 UTF-8 编码。
考虑到上面这些以及类似的情况,我认为一些极限程序员自动删除所有未测试代码的做法是不切实际的,并且可能具有一定的讽刺性。不能总是获得绝对完美的测试覆盖率并不意味着就不会有更好的覆盖率。
然而,比执行不到的语句和方法更常见的是残留代码,它不再有任何作用,并且从代码基中去掉这些代码也不会产生任何影响。有时可以通过使用反射来访问私有成员这样的怪招来测试未测试的代码。还可以为未测试的、包保护(package-protected)的代码来编写测试代码,将测试类放到将要测试的类所在那个包中。但最好不要这样做。所有不能通过发布的(公共的和受保护的)接口访问的代码都应删除。执行不到的代码不应当成为代码基的一部分。代码基越小,它就越容易被理解和维护。
运行 Cobertura
在了解了测量代码覆盖率的好处后,让我们再来讨论一下如何用 Cobertura 测量代码覆盖率的具体细节。Cobertura 被设计成为在 Ant 中运行。现在还没有这方面的 IDE 插件可用,不过一两年内也许就会有了。
首先需要在 build.xml 文件中添加一个任务定义。以下这个顶级 taskdef
元素将 cobertura.jar 文件限定在当前工作目录中:
<taskdef classpath="cobertura.jar" resource="tasks.properties" />
|
然后,需要一个 cobertura-instrument
任务,该任务将在已经编译好的类文件中添加日志代码。todir
属性指定将测量类放到什么地方。fileset
子元素指定测量哪些 .class 文件:
<target name="instrument">
<cobertura-instrument todir="target/instrumented-classes">
<fileset dir="target/classes">
<include name="**/*.class"/>
</fileset>
</cobertura-instrument>
</target>
|
用通常运行测试包的同一种类型的 Ant 任务运行测试。惟一的区别在于:被测量的类必须在原始类出现在类路径中之前出现在类路径中,而且需要将 Cobertura JAR 文件添加到类路径中:
<target name="cover-test" depends="instrument">
<mkdir dir="${testreportdir}" />
<junit dir="./" failureproperty="test.failure" printSummary="yes"
fork="true" haltonerror="true">
<!-- Normally you can create this task by copying your existing JUnit
target, changing its name, and adding these next two lines.
You may need to change the locations to point to wherever
you've put the cobertura.jar file and the instrumented classes. -->
<classpath location="cobertura.jar"/>
<classpath location="target/instrumented-classes"/>
<classpath>
<fileset dir="${libdir}">
<include name="*.jar" />
</fileset>
<pathelement path="${testclassesdir}" />
<pathelement path="${classesdir}" />
</classpath>
<batchtest todir="${testreportdir}">
<fileset dir="src/java/test">
<include name="**/*Test.java" />
<include name="org/jaxen/javabean/*Test.java" />
</fileset>
</batchtest>
</junit>
</target>>
|
Jaxen 项目使用 JUnit 作为其测试框架,但是 Cobertura 是不受框架影响的。它在 TestNG、Artima SuiteRunner、HTTPUni 或者在您自己在地下室开发的系统中一样工作得很好。
最后,cobertura-report
任务生成本文开始部分看到的那个 HTML 文件:
<target name="coverage-report" depends="cover-test">
<cobertura-report srcdir="src/java/main" destdir="cobertura"/>
</target>
|
srcdir
属性指定原始的 .java 源代码在什么地方。destdir
属性指定 Cobertura 放置输出 HTML 的那个目录的名称。
在自己的 Ant 编译文件中加入了类似的任务后,就可以通过键入以下命令来生成一个覆盖报告:
% ant instrument
% ant cover-test
% ant coverage-report
|
当然,如果您愿意的话,还可以改变目标任务的名称,或者将这三项任务合并为一个目标任务。
结束语
Cobertura 是敏捷程序员工具箱中新增的一个重要工具。通过生成代码覆盖率的具体数值,Cobertura 将单元测试从一种艺术转变为一门科学。它可以寻找测试覆盖中的空隙,直接找到 bug。测量代码覆盖率使您可以获得寻找并修复 bug 所需的信息,从而开发出对每个人来说都更健壮的软件。
分享到:
相关推荐
标题中的“用 Cobertura 测量测试覆盖率”指的是在软件开发过程中使用 Cobertura 工具来评估代码的测试覆盖率。测试覆盖率是衡量测试质量的重要指标,它表示代码中被测试用例执行到的比例。Cobertura 是一个开源的 ...
示例build文件 博文链接:https://zhupan.iteye.com/blog/200878
Cobertura 是一种开源测试工具,它通过检测基本的代码,并观察在测试包运行时执行了哪些代码以及哪些代码没有执行,来测量测试覆盖率。除了找出未测试到的代码并发现 BUG 外,Cobertura 还可以通过标记无用的、执行...
测试覆盖率工具是软件开发过程中的重要辅助手段,主要用于评估测试的质量和完整性。它能帮助开发者了解测试用例执行后,代码被触及的程度,确保代码的各个部分都得到了充分的验证。在本文中,我们将深入探讨测试覆盖...
Cobertura通常通过Ant脚本来集成到项目中,以便在持续集成或开发过程中自动测量代码覆盖率。 关于“源码”标签,这表明Cobertura不仅是一个二进制工具,还提供了源代码,允许用户查看、修改和扩展其功能。这对于...
它能够帮助开发者测量和报告程序代码的测试覆盖率,即多少代码被单元测试执行过。这对于确保软件的质量和可靠性至关重要,因为未经过测试的代码可能会隐藏潜在的错误。 在描述中提到的"ant+junit+cobertura的build....
Cobertura是一款开源的Java代码覆盖率工具,它用于测量Java程序单元测试的覆盖率。这个"cobertura-1.9.4.1-src.zip"压缩包包含的是Cobertura 1.9.4.1版本的源代码。源代码是任何软件开发的基础,它允许开发者深入...
Cobertura 是一个用于 Java 代码覆盖率测试的工具,它能够帮助开发者测量和跟踪他们的源代码有多少被单元测试覆盖。 在描述 "cobertura-1.9.4.1-bin.zip" 中,没有额外的具体信息,但我们可以推断这可能是一个 ZIP ...
- 如JaCoCo或Cobertura,用于测量代码的测试覆盖率,帮助确保测试的全面性。 7. **Mocking和Stubbing**: - 如使用Mockito的`when()`和`thenReturn()`方法来定义mock对象的行为。 8. **数据库测试**: - 使用`@...
8. 覆盖率工具:JaCoCo、Cobertura等可以帮助测量测试覆盖率,确保足够的代码得到了测试。 9. 测试驱动开发(TDD):一种开发实践,先写测试,再编写满足测试的代码,有助于提高代码质量。 10. 持续集成:Jenkins、...
它是流行的 JSCoverage工具的增强版本,增加了一些功能,包括分支覆盖率、 LCOV和用于 CI 集成的Cobertura XML报告、用于自动化测试的钩子和HTML 本地存储,以在不使用 iFrame 或 JavaScript 打开的窗口的情况下维护...
Cobertura不仅支持基本的覆盖率类型,还提供了一种称为“包装器覆盖率”的高级功能,用于测量测试代码对第三方库的覆盖情况。 使用代码覆盖率工具的目的是为了更好地实现测试驱动开发(TDD)和持续集成(CI),确保...
9. 测试覆盖率工具:学习使用JaCoCo或Cobertura等工具来测量测试覆盖率,以评估测试的充分性。 通过这个毕业设计,你不仅掌握了TDD的基本技能,还深化了对Java编程和软件开发最佳实践的理解。这种经验将对你的未来...
- JaCoCo:用于测量Java代码覆盖率的工具,帮助确保测试覆盖了大部分代码。 - Cobertura:类似的代码覆盖率工具,提供报告来分析测试覆盖情况。 6. 性能测试工具: - JMeter:Apache项目,用于性能和负载测试,...
11. **代码覆盖率**:通过工具如Cobertura或JaCoCo,可以测量测试用例覆盖了多少源代码,以评估测试的全面性。 12. **Spring Boot测试支持**:Spring Boot提供了丰富的测试注解,如`@RunWith(SpringRunner.class)`...
8. **代码覆盖率**:工具如JaCoCo或Cobertura用于测量测试覆盖了多少代码行,帮助开发者确定哪些部分可能需要更多的测试。 9. **Mocking**:在测试中,mock对象可以帮助隔离系统组件,模拟依赖关系,使测试更加可控...