导语:

Yuanhao Ji 同学是《暑期 2021 - API 模块 UT 测试问题解决》项目负责人,本文记录了他是如何排查和定位问题。

1. 背景

问题:在部分 UT 中使用 PowerMock 后,导致 Sonar 不能获取对应的测试报告。

大概原因:PowerMock 模拟 JDK 的静态方法、构造方法、final 方法、私有方法时,需要把使用这些方法的类加入到 @PrepareForTest 注解中,从而导致单元测试覆盖率不被统计。

2. 思路

2.1 明确问题出处,缩小定位范围

DolphinScheduler UT 中使用了 PowerMock 作为单元测试模拟框架,由 JaCoCo 统计各项覆盖率指标,最后由 Sonar 存储和管理覆盖率数据。而问题表现为 —— Sonar 中的某些 UT 覆盖率为 0,但是 Sonar 只是一个代码质量管理平台,覆盖率数值并不是由它得出的,Sonar 只是读取了 JaCoCo 生成的测试报告。那么,很容易看出,这个问题一定与 JaCoCo 脱不了干系。

进一步观察发现,并非所有 UT 的覆盖率都有问题,只用到 JUnit 的 UT 就可以正常获取覆盖率,而所有出现覆盖率问题的 UT 都少不了 PowerMock 的影子。

因此,覆盖率问题一定与 PowerMock 和 JaCoCo 有关。

2.2 搜集资料,寻找相似问题

分析问题之后,我们首先可以借助搜索引擎找到与之相似或相同的问题,通过了解这些问题的背景和解决方案也许可以找到我们问题的关键点。

基于以上分析,以 JaCoCo、PowerMock、覆盖率 这三个关键字在 Google、Baidu 等搜索引擎上搜索资料。幸运的是,网上有大量同类问题,并且都与 JaCoCo、PowerMock 有关。

其中,正如 Code-coverage-with-JaCoCo[1] 中所说 —— There is NO WAY TO USE PowerMock with JaCoCo On-the-fly instrumentation。PowerMock 和 JaCoCo 的 On-the-fly instrumentation 之间存在问题。经验证发现,DolphinScheduler 目前正是使用的这两者结合的方式,因此这应该就是问题的关键所在。

2.3 分析问题出现原因

基于搜索结果和官方文档,分析问题出现原因。

首先,如 JaCoCo Class Ids[2] 中的描述,JaCoCo 基于 CRC64 算法计算得到 64 位的 Class Id,用它来标识 Java 类,在运行时为每个加载的类采样执行数据并存储到 *.exec 文件中,在分析时(例如生成报告),Class Id 用于将分析的类与执行数据相关联。

而出现覆盖率为 0% ,就是因为待测试的类与 JaCoCo 实际采样的类不一致,也即通过 CRC64 算法计算的 Class Id 改变,从而导致待测试类的测试报告中覆盖率始终为 0。

那么,为何会出现这种 Class Id 改变的情况呢?上述页面中也给出了答复 —— 这种情况通常发生在配置 JaCoCo 代理之前配置了另一个 Java Agent,或者特殊的类加载器预处理了这些类文件,例如:Mocking frameworks、Application servers、Persistence frameworks。而 PowerMock 就是一种 Mock 框架,进一步了解其原理得知,JaCoCo 在加载 class 时会事先把统计代码插入到 class 中(即插桩),当执行到某个测试类时,PowerMock 检测到该类使用了@PrepareForTest 注解,就会在加载该类时使用 Javassist 直接从 class 文件中重新读取字节码,导致 JaCoCo 的修改丢失,稍后 JaCoCo 统计的 class 是被修改之后的,而被修改之后的 class 中并没有 JaCoCo 所插入的统计代码,并且 class 文件发生变化后 Class Id 也与加载时不一致。在分析时,测试结果无法关联到待测试类,最终导致覆盖率始终为 0。

如下图所示,Demo 类后面还跟有 MockitoMock 的字样,说明这是一个由 PowerMock 模拟的对象,而 JaCoCo 却错把它以为是最开始时所加载的 Demo 类。

2.4 制定解决方案

JaCoCo 的 offline instrumentation 可以解决此类问题,它的原理是这样的:在测试前先对 class 文件进行插桩,然后生成插过桩的 class 文件或 jar 包,测试插过桩的 class 和 jar 包后,生成动态覆盖信息到文件,最后统一对覆盖信息进行处理,并生成报告。

On-the-fly 模式进行代码覆盖分析更方便和简单,无需提前进行字节码插桩,无需考虑 classpath 的设置。

但存在如下情况则不适合 On-the-fly,需要采用 offline 提前对字节码插桩:

(1)运行环境不支持 java agent。

(2)部署环境不允许设置 JVM 参数。

(3)字节码需要被转换成其他的虚拟机如 Android Dalvik VM。

(4)动态修改字节码过程中和其他 agent 冲突。

(5)无法自定义用户加载类。

而目前问题就是因为动态修改字节码过程中与 PowerMock 冲突,因此必须使用 offline 模式。

[1] https://github.com/powermock/powermock/wiki/Code-coverage-with-JaCoCo

[2] https://www.eclemma.org/jacoco/trunk/doc/classids.html

Apache DolphinScheduler 项目笔记 — 1. 问题定位和排查问题的更多相关文章

  1. 感谢有你!Apache DolphinScheduler 项目 GitHub star 突破 8k

    本周伊始,Apache DolphinScheduler 项目在 GitHub 上的 Github Star 总数首次突破 8K.目前,Apache DolphinScheduler 社区已经拥有 C ...

  2. Apache DolphinScheduler(海豚调度) - 1.3 系列核心表结构剖析

    Apache DolphinScheduler 是一个分布式去中心化,易扩展的可视化 DAG 工作流任务调度系统.致力于解决数据处理流程中错综复杂的依赖关系,使调度系统在数据处理流程中开箱即用. 近日 ...

  3. 金灿灿的季节 - Apache DolphinScheduler收获5位新Committer

    在这个金灿灿的收获季节,经过 Apache DolphinScheduler PPMC 们的推荐和投票,Apache DolphinScheduler 收获了 5 位新Committer .他们是:n ...

  4. 金秋十月 - Apache DolphinScheduler 收获 2 位新 Committer

    点击上方蓝字关注 Apache DolphinScheduler Apache DolphinScheduler(incubating),简称"DS", 中文名 "海豚调 ...

  5. 新一代大数据任务调度 - Apache DolphinScheduler喜提十大开源新锐项目 & 最具人气项目

    经 10000+ 开发者公开票选,20+专家评审. 10+ 主编团打分,历经数月打磨,11 月 19 日,由InfoQ 发起并组织的[2020中国技术力量年度榜单评选]结果正式揭晓. 2020 年度十 ...

  6. 【喜讯】Apache DolphinScheduler 荣获 “2020 年度十大开源新锐项目”

    经 10000+ 开发者公开票选,20+专家评审. 10+ 主编团打分,历经数月打磨,11 月 19 日,由InfoQ 发起并组织的[2020中国技术力量年度榜单评选]结果正式揭晓. 2020 年度十 ...

  7. 大数据平台迁移实践 | Apache DolphinScheduler 在当贝大数据环境中的应用

    大家下午好,我是来自当贝网络科技大数据平台的基础开发工程师 王昱翔,感谢社区的邀请来参与这次分享,关于 Apache DolphinScheduler 在当贝网络科技大数据环境中的应用. 本次演讲主要 ...

  8. Apache DolphinScheduler 2.X保姆级源码解析,中国移动工程师揭秘服务调度启动全流程

    2022年1月,科学技术部高新技术司副司长梅建平在"第六届中国新金融高峰论坛"上表示,当前数据量已经大大超过了处理能力的上限,若信息技术仍然是渐进式发展,则数据处理能力的提升将远远 ...

  9. Apache DolphinScheduler 3.0.0 正式版发布!

    ​  点亮 ️ Star · 照亮开源之路 GitHub:https://github.com/apache/dolphinscheduler   ​ 版本发布 2022/8/10 2022 年 8 ...

随机推荐

  1. 学习Java的第十七天——大数字运算

    学习内容:大数字运算 代码实现: package 数字处理类; import java.math.BigInteger; public class BigIntegerDemo { public st ...

  2. 【雅礼集训 2017 Day2】棋盘游戏

    loj 6033 description 给一个\(n*m\)的棋盘,'.'为可通行,'#'为障碍.Alice选择一个起始点,Bob先手从该点往四个方向走一步,Alice再走,不能走走过的点,谁不能动 ...

  3. 背包,子集和以及 (max, +) 卷积在特殊情形下的求法

    背包,子集和以及 (max, +) 卷积在特殊情形下的求法 子集和 1:总重量不太大 有 \(n\) 个物品,每个物品重量为 \(w_i\),且 \(\sum\limits_{i} w_i=C\).你 ...

  4. WC2021 题目清单

    Day2 上午 <IOI题型与趣题分析> 来源 题目 完成情况 备注 IOI2002 Day1T1 Frog 已完成 IOI2002 Day1T2 Utopia IOI2002 Day1T ...

  5. 深度学习与CV教程(12) | 目标检测 (两阶段,R-CNN系列)

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/37 本文地址:http://www.showmeai.tech/article-det ...

  6. 使用Redis实现购物车功能

    增加购物车商品 假设ID为1001的向购物车中存放了3个商品,产品ID分别为10021.10025.10079 hset cart:1001 10021 1 hset cart:1001 10025 ...

  7. 【python】tile函数简单介绍

    转:https://blog.csdn.net/april_newnew/article/details/44176059格式:tile(A,reps)* A:array_like* 输入的array ...

  8. RPA应用场景-海关报关

    场景概述海关报关 所涉系统名称海关页面,业务核心系统 人工操作(时间/次) 10 分钟 所涉人工数量 3 操作频率实时 场景流程 1.每日接收报关申请邮件: 2.根据邮件信息进入业务核心系统查询相关数 ...

  9. kubectl 最新常用命令 --V1.24版本

    Kubectl 自动补全 BASH source <(kubectl completion bash) # 在 bash 中设置当前 shell 的自动补全,要先安装 bash-completi ...

  10. 使用dnSpy对无源码EXE或DLL进行反编译并且修改

    背景 总有一些特殊情况,我们没有源码,但是某个C#程序集dll或者可执行程序exe影响到我们代码的正常运行,我们希望得到源码,能改掉或者修改某些bug,但是苦于没有源码,这个时候可以用dnspy进行源 ...