精准测试 & Jacoco 代码覆盖率统计实战

精准测试介绍

测试现状

测试设计阶段

  • 测试范围

    • 评估少:质量差
    • 评估多:成本高
  • 测试设计

    • 设计全:成本高
    • 设计少:用时少、风险高

交付测试阶段

  • 开发工程师
    • 顺手改了代码,忘记同步,对上线有什么影响?
    • 马上要上线了,系统达到质量标准了么?
  • 测试工程师
    • 核心功能是否回归足够?
    • 功能点这么多,测完还会有遗漏测试点么?
    • 代码变动太频繁,上线会有什么风险么?

于是引出想解决的问题

  • 这次版本新增/修改的代码,都有测试覆盖到吗?
  • 上线前的回归,怎样弄清楚测试范围?

什么是精准测试?

精准测试的目标

  • 降低测试成本:根据代码变更定位测试范围
  • 提高测试覆盖率:更准确覆盖被测业务
  • 提高测试用例有效性:反推有效测试用例

精准测试的应用

  • 测试用例
    • 利用线上数据反推有效测试用例
    • 利用灰度公测
  • 语法树
    • 根据研发代码的变更,筛选精准测试用例
    • 利用代码和调用链,来反向完善测试用例

Jacoco 代码覆盖率统计实战

Jacoco 简介

什么是 Jacoco ?

  • Jacoco 是一个免费的 Java 代码覆盖率统计工具,它是由 EclEmma 团队根据多年来使用和集成现有库的经验教训创建的。

常见的 Java 代码覆盖率统计工具:

  • Jacoco
  • Cobertura(维护较少)
  • Emma(基于 Jacoco)

为什么选择 Jacoco ?

官方解释:
有几种可用的 Java 开源覆盖技术在实现 Eclipse 插件 EclEmma 时,观察到它们都不是真正为集成而设计的。它们中的大多数专门适用于特定工具(Ant 任务、命令行、IDE 插件),并且不提供允许嵌入不同上下文的文档化 API。两个最好的和广泛使用的开源工具是 EMMA 和 Cobertura。这两个工具都不再由原作者积极维护,也不支持当前的 Java 版本。由于缺乏回归测试,维护和功能添加很困难。

Jacoco 特点:

  • 覆盖率分析指标丰富
  • 可以不依赖源代码
  • 集成方式灵活
  • 开发框架无关
  • 兼容所有的java 版本
  • java kotlin scala 等多种 jvm 语言支持
  • 多种报告格式
  • 允许远程控制
  • 有独立的工具与 ant maven 的集成支持

Jacoco 支持的覆盖率指标

  • 指令覆盖率 Instructions
  • 分支覆盖率 Branches
  • 圈复杂度覆盖率 Cyclomatic ComplexityV(G) = e-n+2p
  • 代码行覆盖率 Lines
  • 方法覆盖率 Methods
  • 类覆盖率 Classes

Jacoco 不支持的覆盖率指标

  • 条件覆盖率(Conditioncoverage):每一个逻辑表达式中的每一个条件(无法再分解的逻辑表达式)是否都有运行到成立及不成立的情形。
  • 条件/判断覆盖率(Condition/decisioncoverage):需同时满足判断覆盖率和条件覆盖率。
  • 修改条件/判断覆盖(modifed condition/decision coverage):简称 MC/DC,即在影响判断结果的条件中,每个变量都出现至少二次,其中至少一次其值为真,至少一次其值为假。
  • 循环覆盖率(Loopcoverage):所有循环是否都有运行过零次、一次及一次以上的测试。
  • 参数值覆盖率(Parameter Value Coverage):对于一个方法的所有参数,是否有运行过其中最常见的数值?

代码插桩技术 ASM

字节码

什么是字节码?

image

可以使用 JDK 自带的javap工具来查看字节码相关信息:

C:\Users\JUNOLU\IdeaProjects\Demo\target\classes>javap --help
用法: javap <options> <classes>
其中, 可能的选项包括:
  -help  --help  -?        输出此用法消息
  -version                 版本信息
  -v  -verbose             输出附加信息
  -l                       输出行号和本地变量表
  -public                  仅显示公共类和成员
  -protected               显示受保护的/公共类和成员
  -package                 显示程序包/受保护的/公共类
                           和成员 (默认)
  -p  -private             显示所有类和成员
  -c                       对代码进行反汇编
  -s                       输出内部类型签名
  -sysinfo                 显示正在处理的类的
                           系统信息 (路径, 大小, 日期, MD5 散列)
  -constants               显示最终常量
  -classpath <path>        指定查找用户类文件的位置
  -cp <path>               指定查找用户类文件的位置
  -bootclasspath <path>    覆盖引导类文件的位置

C:\Users\JUNOLU\IdeaProjects\Demo\target\classes>
C:\Users\JUNOLU\IdeaProjects\Demo\target\classes>javap Demo.class
Compiled from "Demo.java"
public class Demo {
  public Demo();
  public static void main(java.lang.String[]);
}

字节码变更

image

image

字节码操作常用框架

  • cglib
  • javassist
  • bytebuddy
  • byteman
  • jvm-sandbox
  • asm(jacoco 的底层实现)

image


插桩原理

  1. 对 JVM 的字节码插桩
  2. 基于代码块(block)插桩(如图中的探针 P)
  3. 计算所覆盖的代码块

image


插桩方式

推荐方式:Java Agent

image

image

On-The-Fly 即时插桩模式

  1. 修改 jvm 启动参数加入 java agent。
  2. 加载 java agent 的逻辑运行在 java 的主方法之前。
  3. java agent 在类加载期间修改类并进行插桩。
  4. java 主方法运行时,所有类已经被插桩,运行后生成覆盖率数据。

image

Offline 离线插桩模式

在测试前先对文件进行插桩,然后生成插过桩的 class 或 jar 包。在测试插过桩的 class 和 jar 包后,会生成动态覆盖信息到文件,最后统一对覆盖信息进行处理,并生成报告。

  • 不支持 java agent
  • 不支持配置 jvm 参数
  • 字节码不兼容的平台
  • 与其他 agent 冲突

两种插桩方式对比

  • On-the-fly 无需提前进行字节码插桩。
  • On-the-fly 无需停机(Offline需要停机),可以实时获取覆盖率。
  • On-the-fly 能更加方便获取代码覆盖率,但是其代理服务会对被测应用造成一定的性能损耗。

jacoco 实战

演练环境

jacoco 使用

1)加入插桩

启动被测应用,并设置覆盖率统计方式为 tcp 模式:

java -javaagent:$JACOCO_HOME//lib/jacocoagent.jar=output=tcpserver  \
  -jar $TARGET_HOME/target/start-site-exec.jar

进行页面操作:

image

2)dump:覆盖率数据导出

覆盖率数据文件名示例:testcase.exec

  • 清空(之前的)并生成最新的覆盖率数据:
rm testcase.exec
java -jar $JACOCO_HOME/lib/jacococli.jar \
  dump \
  --address 127.0.0.1 --port 6300 \
  --reset \
  --destfile testcase.exec
  • 不清空(之前的)并生成最新的覆盖率数据:
java -jar $JACOCO_HOME/lib/jacococli.jar \
  dump \
  --address 127.0.0.1 --port 6300 \
  --destfile testcase.exec

3)report:生成覆盖率报告

生成覆盖率报告并关联源码:

java -jar $JACOCO_HOME/lib/jacococli.jar  \
  report testcase.exec \
  --html jacoco_report \
  --xml jacoco.xml \
  --csv jacoco.csv \
  --classfiles $TARGET_HOME/target/classes/ \
  --sourcefiles $TARGET_HOME/src/main/java/

打开报告目录中的 index.html,查看覆盖率情况:

image

image

  • 绿条:表示已覆盖的代码行。
  • 黄条:表示其下分支有未被覆盖的代码行。
  • 红条:表示未被覆盖的代码行。
posted @ 2022-06-22 20:46  Juno3550  阅读(5103)  评论(0编辑  收藏  举报