折腾Android覆盖率,使用Jacoco的各种坑

目的

对于手工客户端覆盖率来说,Android相对于iOS要好做很多。自带的Jacoco Plugin能很方便得入手和获取报告。
不过其中还是有很多坑的,这里进行一下遇到的坑总结。
之前对手工覆盖率的实现我写过Blog,可参考以下。
简书-手工覆盖率

覆盖率实现基础

Jacoco的覆盖率实现需要两项原始数据。
1. sourceDirectories
2. classDirectories

sourceDirectories对应的是具体的源码Java文件,一般在app/src/main/java等位置。需要注意,要找到的是以java结尾的文件夹
classDirectories对应的是编译完毕后的中间产物,一般在app/build/intermediates/javac/classes等位置。需要注意,要找到的是以classes结尾的文件夹
你问我为啥?我也不知道……还求高人指点。官方文档里只有一行描述:“这是要用到的原始数据”,再下探细节实在费劲了
Gradle-官方Jacoco描述

需要注意的是,Jacoco在Gradle中是作为一个引入的插件。Jacoco自身是一个资源库,Gradle又对这个资源库进行了一系列封装。
Jacoco-官方描述

看过上面手工覆盖率教程后你应该能了解到,Android中实现统计手工覆盖率实际需要以下几个内容
1. Gradle中引入JacocoTestReport task,基于JacocoReport(即 type JacocoReport)
2. 执行方法,通过agent新建ec文件

1
2
3
Object agent = Class.forName("org.jacoco.agent.rt.RT")
	.getMethod("getAgent")
	.invoke(null);

经过简单的测试,我发现
对于手工覆盖率,打包编译时会执行jacocoTestReport,但实际上无作用。该Task只需要提取出ec文件单独执行时正常即可

深坑:classDirectories

看上去简单,但是对于我来说实际上踩坑不少。
不过总结下来,主要都集中于classDirectories这一步。

由于公司的Android仓库进行了插件化处理(可以看看这位博主写的系列介绍,很详细简书-Android插件化),并且有多个打包方案,classDirectories特别分散且再classes文件夹前面还有${BuildType}/compile${BuildType}WithJavac这样的父文件夹,很是麻烦。

本来想找Jacoco Plugin中自带的一些方法来找classDirectories,可以参考StackOverFlow中的问题StackOverFlow-Filter JaCoCo coverage reports with Gradle以及问题作者的GithubGithub-Jacoco Task
主要内容为

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
afterEvaluate {
    classDirectories = files(classDirectories.files.collect {
        fileTree(dir: it,
                exclude: ['codeeval/**',
                          'crackingthecode/part3knowledgebased/**',
                          '**/Chapter7ObjectOrientedDesign**',
                          '**/Chapter11Testing**',
                          '**/Chapter12SystemDesignAndMemoryLimits**',
                          'projecteuler/**'])
    })
}

可惜公司的库用的Gradle版本是4.6,实测编译会出错。以上代码应该只能在Gradle5.0以上使用。

classDirectories一定要具体到classes文件夹,无奈只能自己写方法了。

gradle中使用的是groovy语言,可以参考Groovy-语法