前言
代码覆盖率(Code coverage)是软件测试中的一种度量方式,用于反映代码被测试的比例和程度。
在软件迭代过程中,除了应该关注测试过程中的代码覆盖率,用户使用过程中的代码覆盖率也是一个非常有价值的指标,同样不可忽视。因为伴随着业务扩展和功能更新,产生了大量过时和废弃的代码,这些代码或者很少甚至完全不再使用,或者“年久失修”,缺少维护,不仅对应用包体积有影响,还可能带来稳定性风险。此时,能够采集生产环境的代码覆盖率,了解线上代码的使用情况,为下线无用代码提供依据,就十分重要了。
目标
我们的目标很明确:根据云端配置,采集线上每个类的触达和使用频次,上传到云端,在平台进行处理,并提供查询和报表展示能力。
如上图所示,我们期望代码覆盖率数据能在平台上进行查询和直观的展示,在需要时可以直接查看,为下线旧代码、资源调度和分配等提供决策依据,最终为用户提供更小的App安装包,更好的功能使用体验。
通过云控中心,我们可以控制是否启用覆盖率采集,也可以根据覆盖率(类使用频次)动态调整App中金刚位、线程等资源的调度分配策略。其中覆盖率采集方案是最为重要的一环,业界也有很多成熟的方案,但都有各自适合的场景,而我们的诉求是在尽量不影响用户使用和App运行的前提下,采集类粒度的代码使用覆盖率。使用的采集方案应该少Hack,实现简单,兼顾稳定性和性能,同时也不会侵入打包流程,带来包体积影响等,在经过深入探索后,我们自研出了一套完美满足这些要求的全新方案。
方案对比
下表为常见方案与自研方案的各项指标对比,绿色表示更优。
从表格中可以看出:
Jacoco方案
类似的还有Emma、Cobertura等,他们都通过插桩实现,可以支持所有版本所有粒度的采集,但是插桩带来了一定的包体积和性能影响,不适合线上大范围使用。
Hook PathClassLoader方案
实现简单,无源码侵入,且支持所有Android版本,但Hook PathClassLoader不仅带来了性能影响,甚至可能波及App稳定性。
Hack访问ClassTable方案
能够按需采集,对App性能几乎没有影响,但Hack可能带来兼容性问题,且实现较复杂。
自研方案
性能优异,支持按需采集,无损App性能
实现简单,未使用任何“黑科技”,稳定性和兼容性极好
支持跨进程和插件采集
对比得知自研方案能更好的满足我们采集线上代码覆盖率的诉求