通用技术 jacoco 代码覆盖率使用中遇到的一些坑

Ramsey · November 19, 2018 · Last by Ramsey replied at May 09, 2019 · 1872 hits

今年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文件,这样可以保证本地和服务端的始终都是一致的。

这些问题并不是很复杂,但是如果你只是按照教程去配置代码覆盖率还是会遇到的一些因为实际使用场景而无法预期的坑。所以记住配置说明文档也不是万能的。

共收到 4 条回复 时间 点赞

这两个点确实是实践中需要特别留意的。不准确的覆盖率很容易在前期失去用户的信任。

全量代码覆盖率? 针对于第一个问题15分钟job拉取还是会有覆盖率数据丢失的问题,建议在部署前主动拉取覆盖率数据,Jenkins + jacoco太不灵活了,建议把拉取覆盖率、生成报告全部封装成service服务对外提供接口,比如拉取覆盖率封装成http接口(做成异步的),这样就可以很好的嵌入CI流程里

可否把dump的任务放在服务部署的job步骤里面,build.xml里面设置为append追加模式
确保每次服务停止或重启时都会dump数据。

Ramsey #5 · May 09, 2019 作者
莱亚 回复

首先要你在重启或者服务停止前去dump数据,当然你的方案也是可以的。
但是有个风险就是,如果服务自己重启。如果你的服务比较稳定,我觉得也是可行的。
当然这个方案也是基于你每天有个定时任务去执行dump的基础上,毕竟你不可能指望要等到发布服务的时候才去dump覆盖率数据

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up