个人之前在质量部门中负责过APP覆盖率工具的开发和后期的建设维护。这里借着自己又一次进入工作的下一阶段,重新做一次流程的梳理和总结思考。

概述

各个语言大都有其开源的覆盖率框架,可支持通过该语言编写的系统、程序输出其代码的执行情况,也就是代码覆盖率情况。哪些if-else段落已经被执行、哪一行代码是否已经执行等,都可以通过覆盖率框架准确了解。具体的框架,如Java的Jacoco、objective-c的llvm-SanitizerCoverage等,都是很成熟并且大量使用的框架。

对于测试团队来说,这些框架可以让黑盒测试白盒化,即功能测试完需求后可生成覆盖率报告来验证到底测试覆盖了哪些代码,哪些又没有覆盖到;自动化Case执行后,也可以结合覆盖率报告来看其执行代码的百分比等。

这里我们的原始诉求,即想直接通过现有的覆盖率框架,在每次APP功能测试完毕后查看需求新增代码的覆盖情况。

不过,在实际调研后,发现直接使用会有诸多不便:

  1. 由于框架提供的覆盖率报告是全量的,即每次生成覆盖率报告时,都是针对APP/后端的所有代码。若直接用框架生成的报告来看需求测试情况就会十分麻烦:一次需求新增的代码文件实际就那小几十/十多个,每次查看覆盖情况却需要从几百上千文件的总报告里一层一层点击选择,来查看新增文件情况。
  2. 每次需求新增的代码文件具体是哪些,也需要登录到VCS代码仓库里查找。原始的框架是不包含这方面的功能的。
  3. 需求测试时的代码并非永恒不变的,在功能测试过程中,总会有bugfix或者小细节修正的代码新增,会使得每次覆盖率报告的子页面变更。功能测试查看代码覆盖率的情况大都为测试完毕后查看覆盖总量,为此需要做覆盖率报告的合并。但框架只能合并同版本代码,不同版本代码由于覆盖率实现原理,是无法直接进行合并的。

基于上述种种原因,我们最终选择开发自己的APP增量覆盖率工具,用于客户端双端(Android iOS)的功能测试环节。

工具流程

我们的诉求是开发制作一套工具,在每次需求的功能测试环节使用。使用的目的则为特功能测试时的黑盒测试结果白盒化,即将手工功能测试和具体代码关联上。通过查看增量报告里的覆盖情况,即可清晰了解到手工測试对于代码的覆盖量,以及手工测试未覆盖的代码具体是哪些,便于进行更全面的测试。
为了实现上述诉求,我们的实现方式为:在APP端增加覆盖率上传按钮,点击按钮后即上传覆盖率文件到测试平台。测试平台会基于上传的文件生成覆盖率报告,并且处理多报告合并、不同版本报告合并等。

增量覆盖率工具使用流程

实现方案

实现上述工具实际需要多端开发。包含APP(Android iOS)后端、前端以及数据库、以下为粗略的实现方案。

增量覆盖率实现流程

为实现上述方案,对隔断进行相关开发:

客户端(Android iOS)

数据相关

  • jenkins中新增内容存储: 编译后原始代码和中间产物保存在jenkins服务器中

代码相关

  • 覆盖率框架引入debug编译
  • Debug包新增隐藏按钮、按钮点击触发生成覆盖率文件并上传到后端对应api
  • 客户端中增加编译版本标记,用于报告生成时的版本对应

服务端

数据相关

  • 存储覆盖率文件
  • 存储Jenkins构建与git diff的映射关系

代码相关

  • 编写接收覆盖率文件API
  • 调用覆盖率文件生成覆盖率全量报告
  • 基于全量报告和git diff生成增量报告
  • 生成增量报告的队列处理(每次增量报告生成时间再10s-2mins)
  • 增量报告的多场景合并

主要的难点、诉求与解决

Jenkins存储指数级增长问题

编译APK并产出在原本的流程中只需要保留APK即可,但是在要使用覆盖率工具后,除了APK,还需要存储源代码和大量的中间产物。 源代码在删除了git相关内容后已然不大,但中间产物有几个G的大小。Jenkins构建在测试周期时很频繁,并且打包的APK完成整个测试周期少则几天多则需要一周,存储的量级将指数级增长,因此需要进行删减。

解决方案

由于最终只需要查看增量覆盖率报告,非增量部分均可忽略。故需要将非增量部分的中间产物做删除处理。 简洁的方案为:统一删除掉基本不会变更的框架部分代码中间产物即可。更复杂的可以和git做配合,仅保留增量代码相关的中间产物。

增量报告的多场景合并问题

覆盖率报告的合并可以直接通过jacoco原有方法解决,但是不同版本的覆盖报告无法通过jacoco合并(中间码不同,标记不同,相当于两个报告是完全不一样的东西,无法合并)。这里最简便的方案即为行覆盖合并。 运行过程中会有许多场景,需要分别做处理。 如,已有从旧到新的A版本、B、C版本。

  • 场景1:先上传了A版本覆盖率后,生成增量报告。又上传了A版本覆盖率,同版本做合并。
  • 场景2:先上传了B版本覆盖率后,生成增量报告。另一位测试同学使用了老版本包A版本进行测试,并提交了覆盖率文件。这时需要基于新版本做老版本的合并。
  • 场景3:先上传了B版本的覆盖率后,生成增量报告。另一位测试同学使用了新版本包C版本进行测试,并提交了覆盖率文件。这时需要基于老版本做新版本的合并。