前言

今天在家翻了翻以前的文档,偶然看到了以前用 emma 统计代码覆盖率时总结的一些东西。便突然有了兴致来讨论一下。相信大家都知道有 code coverage 这东西,也研究过。 但大部分公司基本都没有使用 code coverage 或者 code coverage 变成了没什么卵用的 KPI 产物。我总结了一下如果你想最大的发挥 code coverage 这种策略的威力,需要做的几个比较重要的点。

理解 code coverage 能做什么

再讲这些点之前,我们讨论一下 code coverage 能带来什么好处吧。

  1. 首先,它是我们质量保障中重要的一环。别指望单凭它就能证明你的产品没问题,但是它确实是一个重要的指标。它告诉我们,哪些逻辑被执行过了,哪些逻辑没有被执行过。通过分析报告,我们可以补充测试用例,可以去测试那些我们实现没有想到的路径。众所周知,未测试的代码在线上是危险的。
  2. 然后,它可以帮助我们定位 bug 路径。因为它清楚的告诉你,执行一个操作的代码走向。如果你看过我的另一篇帖子论自动化测试脚本的质量与效率。你可以发现 code coverage 配合被测功能的隔离 绝对是定位 bug 的利器
  3. 再然后,可以说它是我们发布之前最后的一关了。虽然即使 100% 的覆盖率都不能保证你的产品是没问题的,但起码能告诉你,你都测试了哪些逻辑。让你的心里有底。一些不错的团队都把覆盖率列为一项指标。我们说当我们的自动化测试的覆盖率比较高的时候,我们的产品就有了不错的自测性。有人称之为产品的保护伞。尤其是非互联网行业,例如在下这个 to B 业务为主的公司。没办法去搞什么众测,灰度和监控的。在产品进入客户公司的场地内之前,就必须要保证产品的质量。所以代码覆盖率,是一个很重要的指标。
  4. 最后,通过分析代码覆盖率报告,我们可以优化代码的质量,当然这部分工作一般都是开发做的。例如找到一些 dead code,废弃的功能等等。可叹的是几乎没有开发有这个闲工夫去搞这些

一些提高效率的点

高度自动化

想搞代码覆盖率,第一个前提是你的项目有能力用自动化的方式把覆盖率提高到一个量级。额,这个应该是个共识吧,除非你人力多到没地方用了。

单元测试

为了实现高覆盖率,必须要有单元测试。实际上,提升覆盖率的主力就是在单元测试这边。如果项目中的开发人员没有编写单元测试的习惯的话,几乎是注定了在覆盖率方面有很大的缺陷了。从实现成本上看,单元测试的 mock 技术是提高覆盖率的不二利器。想只靠测试人员在接口和 UI 级别将覆盖率提高到一定量级是需要极其庞大的成本的。而且有很多逻辑在测试环境中是根本覆盖不了的,所以我们才需要 mock。《Google 软件测试之道》一书中推荐的单元测试的覆盖率在 50%~70% 之间,可惜实际上我没听过几个国内的公司能再单元测试上把覆盖率提高到这个份上

测试人员要熟悉产品代码

导致代码覆盖率变成 KPI 产物的最大一个原因就是测试人员不熟悉产品代码,甚至根本看不懂覆盖率报告。这样根本无法根据报告补充 case,定位 bug。 代码覆盖率也就变成了摆设。

EMMA 的使用

java 中比较流行的代码覆盖率工具有 EMMA,Cobertura,jacoco 等。其实以现在情况来看,使用 jacoco 的人群是比较多的,有点大势所趋的感觉。本来以前用 EMMA 的人很多,但是开发这个工具的坑爹团队自从 2005 年以后就再也没更新过了。可以理解为 EMMA 已经是一个 dead project。但是我从以前就再用 EMMA,所以也一直没换,反正能满足需求就行了。至于到底哪个工具更高大上,我倒不是很在意。不过我还是建议刚搞代码覆盖率的同学直接去搞 jacoco 吧。毕竟 EMMA 都停止更新了,以后肯定会被淘汰的。不过其实所有代码覆盖率的原理都是差不多的,我们说一下 EMMA 的使用也并无不可,而且说实话 EMMA 使用起来确实太简单了,新手首选。

与 maven 集成

java 项目大多都是用 maven 管理的,如果我们想统计单元测试的覆盖率的话,通过 emma 与 maven 集成是最简单不过的。不像 jacoco 那么麻烦,配置 emma 十分简单。只需要添加如下依赖:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>emma-maven-plugin</artifactId>
    <version>1.0-alpha-3</version>
    <inherited>true</inherited>
</plugin>

然后运行命令:mvn emma:emma。 之后你就可以看 report 了

与 jenkins 集成

如果你使用 jenkins 作为 CI 的工具的话,其实就更简单了。你都不用再 pom 文件中增加依赖,安装好 EMMA 的插件以后,直接运行上面的例子的命令就好了。

插桩

上面介绍的都只能统计项目本身的测试,也就是在工程中的 src/test/java 包下面的测试脚本。如果是我们的接口测试,UI 测试呢?我们怎么做才能统计代码覆盖率呢?这就需要一些手段了。

java emma instr -m overwrite -cp simba-1.0.jar -out coverage.em
java emma ctl -connect localhost:47653 -command coverage.get,coverage.ec
java emma report -r html -Dreport.out.encoding=utf-8 -sp /opt/web/simba/src/main/java -in coverage.em,coverage.ec

只要你不删除插桩和收集数据所产生的元数据文件的话。你都可以累计的生成报告。还有一个 merge 模式可以合并报告,详细的东西大家可以去官网看一下。EMMA 的好处就是使用简单。最后我发一个生成的报告的图吧。

总结

OK 就说这么多吧。想把代码覆盖率利用起来真的很难。因为遇到的都是非技术性原因。劝说开发写单元测试,劝说老大把覆盖率加入到质量流程中,劝说产品和其他 QA 关注覆盖率等等。这些哪一个都不容易。即便过了这几关你还要为了提高覆盖率做很大的努力。毕竟项目不会再一开始就开展自动化测试。等自动化测试人员加入到项目中的时候,没准已经遗留了成百上千的接口。这个技术债可能需要以年为单位去还。大家努力吧。

补充一个坑的解决方案

EMMA 有一个坑就是在 jdk1.6 以上的版本有可能出现一个问题,插桩之后运行会出现一个 classformat 异常。提示你参数数量不正确,大概是这个意思吧。其实这是 jdk 在 1.7 以后使用的验证器不一样了。而 EMMA 这个坑爹货太久没有更新了,根本没 cover 到新版本的 JDK。所以需要我们在启动 jvm 的时候增加一个参数。-XX:-UseSplitVerifier。这样就可以了。这个坑当时着实坑了我俩小时。


↙↙↙阅读原文可查看相关链接,并与作者交流