当前位置:首页 > 科技  > 软件

你们单测覆盖率是如何统计的?原理是什么?

来源: 责编: 时间:2024-04-02 17:23:05 119观看
导读高手回答我们在进行单元测试时,经常需要关注一个覆盖率的指标,许多发布流程甚至要求达到特定的百分比。那么,单元测试覆盖率是如何统计的呢?其底层实现原理又是怎样的呢?单元测试覆盖率的统计原理实际上是通过字节码插桩实

高手回答

我们在进行单元测试时,经常需要关注一个覆盖率的指标,许多发布流程甚至要求达到特定的百分比。ixo28资讯网——每日最新资讯28at.com

那么,单元测试覆盖率是如何统计的呢?其底层实现原理又是怎样的呢?ixo28资讯网——每日最新资讯28at.com

单元测试覆盖率的统计原理实际上是通过字节码插桩实现的。也就是说,在编译期间会向代码中注入一些特殊的监控代码,以记录测试执行过程中代码的执行情况,从而推断代码的覆盖情况。这些监控代码能在运行时记录代码的执行情况,也能在编译时生成代码覆盖率报告。ixo28资讯网——每日最新资讯28at.com

常见的单元测试覆盖率统计工具包括JaCoCo、Emma、Cobertura等,这些工具能够在编译或运行时对代码进行插桩,并记录代码的执行情况,最终生成覆盖率报告。ixo28资讯网——每日最新资讯28at.com

具体见下表:ixo28资讯网——每日最新资讯28at.com

工具
ixo28资讯网——每日最新资讯28at.com

Jacoco
ixo28资讯网——每日最新资讯28at.com

Emma
ixo28资讯网——每日最新资讯28at.com

Cobertura
ixo28资讯网——每日最新资讯28at.com

原理
ixo28资讯网——每日最新资讯28at.com

使用 ASM 修改字节码
ixo28资讯网——每日最新资讯28at.com

修改 jar 文件,class 文件字节码文件
ixo28资讯网——每日最新资讯28at.com

基于 jcoverage,基于 asm 框架对 class 文件插桩
ixo28资讯网——每日最新资讯28at.com

覆盖粒度
ixo28资讯网——每日最新资讯28at.com

行,类,方法,指令,分支
ixo28资讯网——每日最新资讯28at.com

行,类,方法,基本块,指令,无分支覆盖
ixo28资讯网——每日最新资讯28at.com

项目,包,类,方法的语句覆盖/分支覆盖
ixo28资讯网——每日最新资讯28at.com

插桩
ixo28资讯网——每日最新资讯28at.com

on the fly、offline
ixo28资讯网——每日最新资讯28at.com

on the fly、offline
ixo28资讯网——每日最新资讯28at.com

offline,把统计代码插入编译好的class文件中
ixo28资讯网——每日最新资讯28at.com

生成结果
ixo28资讯网——每日最新资讯28at.com

在 Tomcat 的 catalina.sh 配置 javaangent 参数,指出需要收集覆盖率的文件,shutdown 时才收集,只能使用 kill 命令关闭 Tomcat,不要使用 kill -9
ixo28资讯网——每日最新资讯28at.com

html、xml、txt,二进制格式报表
ixo28资讯网——每日最新资讯28at.com

html,xml
ixo28资讯网——每日最新资讯28at.com

缺点
ixo28资讯网——每日最新资讯28at.com

需要源代码
ixo28资讯网——每日最新资讯28at.com

1、需要 debug 版本,并打来 build.xml 中的 debug 编译项;2、需要源代码,且必须与插桩的代码完全一致
ixo28资讯网——每日最新资讯28at.com

1、不能捕获测试用例中未考虑的异常;2、关闭服务器才能输出覆盖率信息(已有修改源代码的解决方案,定时输出结果;输出结果之前设置了 hook,会与某些服务器的 hook 冲突,web 测试中需要将 cobertura.ser 文件来回 copy
ixo28资讯网——每日最新资讯28at.com

性能
ixo28资讯网——每日最新资讯28at.com


ixo28资讯网——每日最新资讯28at.com

小巧
ixo28资讯网——每日最新资讯28at.com

插入的字节码信息更多
ixo28资讯网——每日最新资讯28at.com

执行方式
ixo28资讯网——每日最新资讯28at.com

maven,ant,命令行
ixo28资讯网——每日最新资讯28at.com

命令行
ixo28资讯网——每日最新资讯28at.com

maven,ant
ixo28资讯网——每日最新资讯28at.com

Jenkins 集成
ixo28资讯网——每日最新资讯28at.com

生成 html 报告,直接与 hudson 集成,展示报告,无趋势图
ixo28资讯网——每日最新资讯28at.com

无法与 hudson 集成
ixo28资讯网——每日最新资讯28at.com

有集成的插件,美观的报告,有趋势图
ixo28资讯网——每日最新资讯28at.com

报告实时性
ixo28资讯网——每日最新资讯28at.com

默认关闭,可以动态从 jvm dump 出数据
ixo28资讯网——每日最新资讯28at.com

可以不关闭服务器
ixo28资讯网——每日最新资讯28at.com

默认是在关闭服务器时才写结果
ixo28资讯网——每日最新资讯28at.com

维护状态
ixo28资讯网——每日最新资讯28at.com

持续更新中
ixo28资讯网——每日最新资讯28at.com

停止维护
ixo28资讯网——每日最新资讯28at.com

停止维护,不支持java1.8的lamda表达式
ixo28资讯网——每日最新资讯28at.com

什么是字节码插桩

Java字节码插桩技术是指在编译期或运行期,通过修改Java字节码的方式,在代码中插入额外的代码。这种技术可以在不改变Java源代码的情况下,对Java应用程序的运行时行为进行监控、调试、分析和优化等操作。举例来说,它可以用于实现性能监控、代码覆盖率检测、代码安全扫描等功能。ixo28资讯网——每日最新资讯28at.com

字节码插桩技术通常包括以下几个步骤:ixo28资讯网——每日最新资讯28at.com

  1. 生成目标类的字节码,这一步可以通过Java编译器(如javac)或其他工具(如AspectJ)来完成。
  2. 解析字节码,识别需要进行插桩的代码区域(如方法、循环、异常处理等)。
  3. 插入额外的字节码,通常通过编写Java代码来实现这一步,然后利用字节码生成库(如ASM、Javassist等)生成相应的字节码。
  4. 将修改后的字节码重新写回到磁盘或内存中,以供后续使用。

假设我们希望对一个Java方法进行性能监控,我们可以在方法的入口和出口处分别插入计时器,以统计方法的执行时间。以下代码展示了如何实现这一功能:ixo28资讯网——每日最新资讯28at.com

public class Monitor {    public static void start() {        long startTime = System.nanoTime();        // 将起始时间记录到ThreadLocal中,以便在方法返回时进行计算        ThreadLocalHolder.set("startTime", startTime);    }    public static void end() {        long endTime = System.nanoTime();        // 获取起始时间        long startTime = (long) ThreadLocalHolder.get("startTime");        // 计算方法执行时间        long elapsedTime = endTime - startTime;        System.out.println("Method execution time: " + elapsedTime + "ns");    }}public class Example {    public void method() {        Monitor.start();        // 执行方法逻辑        Monitor.end();    }}

然而,若需监控多个方法的性能,分别在每个方法中插入Monitor.start()和Monitor.end()将导致代码重复、可读性下降,并存在遗漏的风险。在这种情况下,可以借助字节码插桩技术,在编译期或运行期间自动向每个方法的入口和出口处插入Monitor.start()和Monitor.end(),以确保代码的统一性和可维护性。ixo28资讯网——每日最新资讯28at.com

具体实现可借助字节码生成库ASM或Javassist来实现,此处以ASM为例。以下代码展示了如何使用ASM对Example类进行字节码插桩:ixo28资讯网——每日最新资讯28at.com

import org.objectweb.asm.ClassReader;import org.objectweb.asm.ClassVisitor;import org.objectweb.asm.ClassWriter;import org.objectweb.asm.MethodVisitor;import org.objectweb.asm.Opcodes;import java.io.IOException;public class MonitorTransformer implements Opcodes {    public static byte[] transform(byte[] classBytes) throws IOException {        ClassReader reader = new ClassReader(classBytes);        ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);        ClassVisitor visitor = new ClassVisitor(Opcodes.ASM5, writer) {            @Override            public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {                MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);                // 只为指定方法添加字节码插桩                if ("method".equals(name) && "()V".equals(desc)) {                    mv = new MethodVisitor(Opcodes.ASM5, mv) {                        @Override                        public void visitCode() {                            super.visitCode();                            // 在方法执行之前插入字节码                            mv.visitMethodInsn(INVOKESTATIC, "Monitor", "start", "()V", false);                        }                        @Override                        public void visitInsn(int opcode) {                            // 在方法返回之前插入字节码                            if (opcode == RETURN) {                                mv.visitMethodInsn(INVOKESTATIC, "Monitor", "end", "()V", false);                            }                            super.visitInsn(opcode);                        }                    };                }                return mv;            }        };        reader.accept(visitor, ClassReader.EXPAND_FRAMES);        return writer.toByteArray();    }}


ixo28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-80882-0.html你们单测覆盖率是如何统计的?原理是什么?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 深度解析Git核心机理,你学会了吗?

下一篇: 代码是如何被被编译的?

标签:
  • 热门焦点
Top