增量代码覆盖率平台开发调研

269 阅读1分钟

背景:测试同学对后端实现不了解,设计的测试用例不够完善没有覆盖到代码,或者由于某些原因导致没有覆盖到代码,最后导致线上隐患。

效果:对于测试的点点点还是自动化测试都能直观的看到哪些分支被测过。

image.png

参考了文末链接里面的资料,总结出大致方案是:

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);
                }
            }
        };
    }

blog.csdn.net/tushuping/a…

tech.kujiale.com/fu-gai-lu-p…

github.com/rayduan/cod…

github.com/didi/super-…

xie.infoq.cn/article/0cb…

juejin.cn/post/713792…

testerhome.com/articles/16…

juejin.cn/post/719018…