今年 5 月离开某易来到新公司之后,一直希望把某易的代码覆盖率带过来,一方面可能之前在某易测试的时候习惯了提测后再检查代码覆盖率来进行补充测试的模式,另一方面新公司是家算不大的中小公司,在测试方面还是一直走比较传统的手工测试的路线,也希望可以改进一下,向精准化测试推进。
代码覆盖率(jacoco)的原理和具体搭建流程网上资料很多,我这里就不详细在陈述了,我这边搭建也是主要按照网上的流程通过 jenkins+jacoco 配置。起初在看到覆盖率数据正常获取,并验证了初步覆盖率结果的准确性后,便把它投入到项目中进行使用。但是在运行一段时间后,组织开发与测试同学一起进行覆盖率分析时还是发现实际数据与真实结果存在一定差异的问题。
首先基于 jacoco 工具本身应该不会存在覆盖率丢失和遗漏的情况,那么为了找到差异的原因,我这边对整个覆盖率统计的过程进行了复盘。
我们是通过 jenkins+jacoco 配置代码覆盖率,设置每天 15 点定时,通过 jenkins 任务去 git 上拉取服务代码,并对代码进行编译生成 class 文件。由于覆盖率统计和项目发布任务都在同一台 jenkins 机器上,所以编译的 jdk 是一致的,确保 class 文件不会有差异。然后通过 ant build.xml 文件去 dump 最新的 exec 文件,并通过 merge 保证覆盖率数据一直增量记录。最后通过 jacoco 插件实现覆盖率数据的正常展示。
表面上我当初搭建的时候觉得这样的安排很合理,但是当细细分析时,还是存在很多遗漏点:
1.覆盖率数据出现丢失:
我们 jenkins 覆盖率任务是每天 17 点定时去 dump 获取 exec 文件,但是我们知道 jacocoagent 由于注入在服务中,随服务的关闭而关闭,所以当服务发布重启时覆盖率数据会出现丢失,比如:服务 A 每天分别在 9 点和 19 点发布 2 次,那我们定时去 dump exec 文件是,明显会丢失从 19 点到 9 点那段时间的覆盖率,而且实际测试过程中由于项目偏敏捷模式,每天的发布频率并无法控制。而且实际除了发布重启之外也可能存在服务器挂掉的情况。
所以为了尽可能的全面的获取到覆盖率数据,我们需要提高 dump exec 的频率。在 jenkins 定时任务不变的情况下,通过编写 python 脚本来实现每 15 分钟去执行 ant build.xml 命令去 dump 最新的覆盖率数据。实际当然也可以把频率提升的更高。这样的方式,可以尽可能规避掉覆盖率数据丢失的情况。
2.覆盖率数据不准确:
大家可能会觉得奇怪怎么区分出覆盖率不准确和丢失的情况,其实是这样的,覆盖率丢失是之前操作了但是没有记录为已覆盖,但是再次操作会记录为已覆盖。覆盖率不准确则是不管怎么操作对应代码都不会记录为已覆盖。基于始终相信 jacoco 工具是不会有错的原则,所以我们可以把问题的焦点放在最容易出现不准的本地与服务端的 class 文件不一致的情况。
jenkins 上的 class 文件是通过 git 上拉取的源码编译而成,由于前期规避了 jdk 版本不一致的问题,所以觉得本地的 class 文件肯定与服务端的保持一致。但是当切入到实际使用时还是存在遗漏。我们每次运行覆盖率任务时从 git 上拉取的都是最新的代码,所以编译的 class 文件也是基于最新的代码。但是实际 dump 过来的 exec 基于的未必是最新的代码,还是因为项目偏敏捷的模式,每天 commit 的代码量会比较大,为了保证项目正常测试不会频繁被打断,所以并不会实时 commit 新代码后立即去发布,这样就导致了你 dump 过来的 exec 是基于之前的版本的代码,从而本地和服务端的 class 是不一致的情况。
当我们认识到这个问题,其实解决也不难,从 git 上拉取代码,改为从 jenkins 上对应服务的发布任务中去拷贝源码和 class 文件,这样可以保证本地和服务端的始终都是一致的。
这些问题并不是很复杂,但是如果你只是按照教程去配置代码覆盖率还是会遇到的一些因为实际使用场景而无法预期的坑。所以记住配置说明文档也不是万能的。