概述
对于 Jacoco 理想的使用场景:在测试阶段,能够实时统计手工测试的代码覆盖率情况
了解了 jacoco 的一些基本使用方法后,发现要满足这个使用场景,至少需要解决 2 个问题。
- 类修改,带来的探针数据合并问题
- 方法的修改,对探针数据造成的影响
下面讲讲具体问题以及解决思路
重点说明:以下实践使用普通 java 类测试,并且我所使用的是 JDK8。大于 JDK8 版本的插桩逻辑并不相同,如果是 JDK9 及以上版本,可能并不适用
问题一
类修改,带来的探针数据合并问题
图 1
如图 1 所示,修改前的 Hello.java 文件,包含 3 个方法:A/B/C,修改后包含 4 个方法:A/B/C/D。
收集修改前 Hello 类的探针数据 (假设 A/B 方法已执行):dump1.exec
修改 Hello 中的 B 方法,然后重新收集探针数据 (假设 C/D 方法已执行):dump2.exec
dump1.exec 和 dump2.exec 的数据合并,想要合并后的覆盖率数据中包括:已被执行方法【A/C/D】,未被执行方法:【B】
合并 exec 数据使用 jacoco 的 merge 指令,merge 对于同一个类文件数据是否能合并的主要判断逻辑代码如下:
public void assertCompatibility(final long id, final String name,
final int probecount) throws IllegalStateException {
/**
这里是我加的注释
同一个java文件,每次修改后对应生成的classId都是不一致的,
所以在这个地方就会被判断不通过,无法合并同一个java文件的统计数据
假设这里注释掉id的判断逻辑,继续往下执行
*/
if (this.id != id) {
throw new IllegalStateException(
format("Different ids (%016x and %016x).",
Long.valueOf(this.id), Long.valueOf(id)));
}
if (!this.name.equals(name)) {
throw new IllegalStateException(
format("Different class names %s and %s for id %016x.",
this.name, name, Long.valueOf(id)));
}
/**
还是我加的注释
如果上面的id判断逻辑注释掉,在这里面探针数组长度的时候还是会校验失败,
Hello.java文件修改后,新增了D方法,导致Hello类文件的探针数据长度是发生了变化,这里长度校验会失败;
假设没有新增D方法,同时假设数组长度刚好一致能够合并。但同时无法过滤掉修改前(dump1.exec)B方法的统计数据
所以仅仅注释掉id的判断逻辑是行不通的
*/
if (this.probes.length != probecount) {
throw new IllegalStateException(format(
"Incompatib