背景:测试同学对后端实现不了解,设计的测试用例不够完善没有覆盖到代码,或者由于某些原因导致没有覆盖到代码,最后导致线上隐患。
效果:对于测试的点点点还是自动化测试都能直观的看到哪些分支被测过。
参考了文末链接里面的资料,总结出大致方案是:
1.定时获取jacoco执行dump命令生成的exec文件,exec是二进制文件,里面有探针的覆盖执行信息, 记录了代码的覆盖情况。
2.当前分支与master分支对比,计算出差异化代码,将差异代码在report阶段连同exec文件传给jacoco。
3.修改jacoco源码,仅对差异代码生成覆盖率报告。
org.jacoco.core.internal.flow.ClassProbesAdapter#visitMethod
public final MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature,
final String[] exceptions) {
final MethodProbesVisitor methodProbes;
final MethodProbesVisitor mv = cv.visitMethod(access, name, desc,
signature, exceptions);
// if (mv == null) {
// // We need to visit the method in any case, otherwise probe ids
// // are not reproducible
// methodProbes = EMPTY_METHOD_PROBES_VISITOR;
// } else {
// methodProbes = mv;
// }
//增量处理
if (null != mv) {
if (this.isDiffClass) {
String methodStr = name + "(" + CheckUtil.getParam(desc) + ")";
if (Objects.isNull(methodPropeCount.get(methodStr))) {
// 已有方法存入
if (methodPropeCount.size() > 0) {
MethodPropeCountRecord record = methodPropeCount.get(methodNameStrTmp);
record.setEndCount(counter - 1);
methodPropeCount.replace(methodNameStrTmp, record);
}
methodNameStrTmp = methodStr;
MethodPropeCountRecord record = new MethodPropeCountRecord();
record.setStartCount(counter);
methodPropeCount.put(methodStr, record);
}
}
// 增量处理
if (null != jacocoMethodInfos && !jacocoMethodInfos.isEmpty()) {
if (CheckUtil.checkMethodIn(this.name, name, desc, this.jacocoMethodInfos)) {
methodProbes = mv;
} else {
methodProbes = EMPTY_METHOD_PROBES_VISITOR;
}
} else {
methodProbes = mv;
}
} else {
methodProbes = EMPTY_METHOD_PROBES_VISITOR;
}
return new MethodSanitizer(null, access, name, desc, signature,
exceptions) {
@Override
public void visitEnd() {
super.visitEnd();
LabelFlowAnalyzer.markLabels(this);
final MethodProbesAdapter probesAdapter = new MethodProbesAdapter(
methodProbes, ClassProbesAdapter.this);
if (trackFrames) {
final AnalyzerAdapter analyzer = new AnalyzerAdapter(
ClassProbesAdapter.this.name, access, name, desc,
probesAdapter);
probesAdapter.setAnalyzer(analyzer);
methodProbes.accept(this, analyzer);
} else {
methodProbes.accept(this, probesAdapter);
}
}
};
}