JAVA 代码覆盖率工具 JaCoCo-原理篇

本文详细介绍了Java代码覆盖率工具JaCoCo的工作原理及使用方法。覆盖了需求覆盖率和代码覆盖率的概念,深入解析了JaCoCo的分支覆盖、Agent模式等特性。并通过对比EMMA工具,展示了JaCoCo的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、 覆盖率定义

作为一个测试人员,保证产品的软件质量是其工作首要目标,为了这个目标,测试人员常常会通过很多手段或工具来加以保证,覆盖率就是其中一环比较重要的环节。

我们通常会将测试覆盖率分为两个部分,即“需求覆盖率”和“代码覆盖率”。

需求覆盖:指的是测试人员对需求的了解程度,根据需求的可测试性来拆分成各个子需求点,来编写相应的测试用例,最终建立一个需求和用例的映射关系,以用例的测试结果来验证需求的实现,可以理解为黑盒覆盖。

代码覆盖:为了更加全面的覆盖,我们可能还需要理解被测程序的逻辑,需要考虑到每个函数的输入与输出,逻辑分支代码的执行情况,这个时候我们的测试执行情况就以代码覆盖率来衡量,可以理解为白盒覆盖。

以上两者完全可以相辅相成,用代码覆盖结果反向的检查需求覆盖(用例)的测试是否充分完整。

如果做覆盖率测试?我们可以借助一些网上流行的各种覆盖率工具,本章主要介绍JaCoCo这个工具。

二、JAVA覆盖率工具介绍

市场上java主要代码覆盖率工具:EMMA、JaCoCo

总结一下个人对JaCoCo优势的理解:

(1)JaCoCo支持分支覆盖、引入了Agent模式。

(2)EMMA官网已经不维护了,JaCoCo是其团队开发的,可以理解为一个升级版。

(3)JaCoCo社区比较活跃,官网也在不断的维护更新。

我们前期使用的EMMA,也做了全量、差异覆盖率,和精准耦合也结合在了一起,但后来考虑到JaCoCo的优势,也就全部切换了过来。

2.1 JaCoCo简述

JaCoCo是一个开源的覆盖率工具(官网地址:http://www.eclemma.org/JaCoCo/),它针对的开发语言是java,其使用方法很灵活,可以嵌入到Ant、Maven中;可以作为Eclipse插件,可以使用其JavaAgent技术监控Java程序等等。

很多第三方的工具提供了对JaCoCo的集成,如sonar、Jenkins等。
JaCoCo包含了多种尺度的覆盖率计数器,包含指令级覆盖(Instructions,C0coverage),分支(Branches,C1coverage)、圈复杂度(CyclomaticComplexity)、行覆盖(Lines)、方法覆盖(non-abstract methods)、类覆盖(classes),后面会一一介绍。

我们先看看其覆盖率结果展现如下图1-1所示,方便读者先有一个大概的了解。

图1-1 覆盖率报告结果部分截图

标示绿色的为行覆盖充分,标红色的为未覆盖的行,黄色菱形的为分支部分覆盖,绿色菱形为分支完全覆盖。

通过这个报告的结果就可以知道代码真实的执行情况,便于我们分析评估结果。

2.2 JaCoCo基本概念

行覆盖率:度量被测程序的每行代码是否被执行,判断标准行中是否至少有一个指令被执行。

类覆盖率:度量计算class类文件是否被执行。

分支覆盖率:度量if和switch语句的分支覆盖情况,计算一个方法里面的

总分支数,确定执行和不执行的 分支数量。

方法覆盖率:度量被测程序的方法执行情况,是否执行取决于方法中是否有至少一个指令被执行。

指令覆盖:计数单元是单个java二进制代码指令,指令覆盖率提供了代码是否被执行的信息,度量完全 独立源码格式。

圈复杂度:在(线性)组合中,计算在一个方法里面所有可能路径的最小数目,缺失的复杂度同样表示测 试案例没有完全覆盖到这个模块。

2.3 JaCoCo 原理

1. 注入方式介绍

这个图包含了几种不同的收集覆盖率信息的方法,每种方法的实现方法都不一样,带颜色的部分是JaCoCo比较有特色的地方。

上面各个名次含义(带颜色的为JaCoCo支持):

上表JaCoCo支持的部分,再详细的解释下:

(1)JaCoCo在Byte Code时使用的ASM技术修改字节码方法,可以修改Jar文件、class文件字节码文件。

(2)JaCoCo同时支持on-the-fly和offline的两种插桩模式。

  • On-the-fly插桩:

JVM中通过-javaagent参数指定特定的jar文件启动Instrumentation的代理程序,代理程序在通过Class Loader装载一个class前判断是否转换修改class文件,将统计代码插入class,测试覆盖率分析可以在JVM执行测试代码的过程中完成。

  • Offline模式:

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

  • On-the-fly和offline比较:

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

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

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

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

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

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

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

2. JaCoCo执行最小的java版本

最小需要Java1.5

3. 字节码处理方式

JaCoCo通过注入来修改和生成java字节码,使用的是ASM库。

4. java方法控制流分析

JaCoCo是如何在字节码注入的?

我们带着疑问来看下面的内容:

先举个实例,有个java方法:

编译后转换成字节码后,内容如下:

我们知道JaCoCo是字节码注入方式,它是通过一个Probe探针的方式来注入的,具体如下:

探针是字节指令集插入到java方法中,程序执行后可以被记录,它不会改变原有代码的行为。

我们看看探针前后插入比较:

颜色的部分就是探针注入的地方。

JaCoCo是根据控制流Type来采用不同的探针插入策略的。

一个用java字节码定义的java方法的控制流图可能有以下的type,每一个type连接一个源指令与目标指令,type不同探针的注入策略也会不同,如下是type定义:

探针不改变该方法的行为,但记录他们已被执行的事实,从理论上讲,可以在控制流图的每一个边插入一个探针,作为探针实现本身需要多个字节码指令,这将增加几倍的类文件的大小和执行速度。

事实上,只需要一个几个探头,根据每个方法的控制流的方法,下面说明了如何在不同的边缘类型的情况下添加额外的指令:

一个instrumented class可以用以下代码检索其探针数组实例:

JaCoCo是用一个布尔数组来实现探针,每个探针对应于该数组中的项。当以下四个字节码指令触发时探针进行输入设置为true:

JaCoCo对行探针是这样处理的,添加两行指令之间的一个额外的探针时,后续行至少包含一个方法调用。

以上是JaCoCo插桩原理,如果想深入了解,可以去看看它的源码实现。

三、JaCoCo使用方式

使用方式有很多,这里贴出了相应的参考链接,根据项目的不同可以灵活供有需要的读者去学习。

3.1 Apache Ant方式

参见 http://eclemma.org/jacoco/trunk/doc/ant.html

主要有以下几种,具体使用就不介绍了,应用宝是用的这种方式,后续有介绍。

Task coverage、Task agent、Task dump、Task merge、Task report、Task instrument

3.2 命令行方式

参见 http://www.eclemma.org/jacoco/trunk/doc/agent.html

使用方式说明:

主要放在JAVA_OPTS中,比如:

由AgentOptions的getVMArgument方法加载,各参数入AgentOptions的对应参数,为后续操作做为输入。

下面是官网的所有参数说明:

系统在jvm停止的时候会dump覆盖率信息。

关键的核心代码在这里,Agent.java在有一段代码

Runtime.getRuntime().addShutdownHook这个方法的意思就是在jvm中增加一个关闭的钩子,当jvm关闭的时候,会执行系统中已经设置的所有通过方法addShutdownHook添加的钩子,当系统执行完这些钩子后,jvm才会关闭。所以这些钩子可以在jvm关闭的时候进行内存清理、对象销毁等操作。

也就是在JVM关闭的时候调用agent.shutdown(),也就是写覆盖率数据。

###3.3 Apache Maven方式
参见 http://www.eclemma.org/jacoco/trunk/doc/maven.html

这种方式适合Maven的项目。

下面简单说下调用方式原理:

就拿官方的Offline Example来说吧,其内容如下:

注意蓝色的部分,上面的配置主要做了以下几个事情:

(1)项目已jar包方式打包,引入junit和jacoco。

(2)Build时执行instrument、report、check。

(3)覆盖率生成到target/jacoco.exec

我们看看他是怎么触发调用的。

在jacoco源码中:jacoco-maven-plugin\target\classes\META-INF\maven\org.jacoco\jacoco-maven-plugin目录下有个plugin-help.xml文件,它里面标明了具体的调用方式。

截出instrument这段,关键地方就是下面蓝色部分。

官网上关于参数的说明:

给出一个整理后的表格:

再给一个jacoco的maven部分的代码目录:

到这里,大家应该清楚其调用的方式了吧。

###3.4 Eclipse EclDmma Plugin方式

具体步骤如下:

(1)在Eclipse菜单中选择Help → Install New Software...

(2)在安装弹框中输入http://update.eclemma.org/,勾选出现的版本。

(3)核对版本,点击Next。

(4)根据向导完成安装。

(5)使用就不说了。

###3.5 与Jekins集成
(1)先要在jenkins上安装JaCoCo的插件,安装完成之后在job的配置项中可以增加这个选项(如图1-2):

图1-2

(2)选择后出现(图1-3):

图1-3

第一个录入框是你的覆盖率文件(exec),第二个是class文件目录,第三个是源代码文件目录。

(3)配置好了之后进行构建,构建完成之后job首页就会出现覆盖率的趋势图(图1-4),鼠标点击趋势图可以看到覆盖率详情(图1-5) ,包括具体覆盖率数据和源码的覆盖率情况:

图1-4 趋势图

图1-5 覆盖率详情

JaCoCo原理篇就介绍到这里了,后续还有项目实践篇和踩坑篇,实践篇主要介绍下JaCoCo在实际业务中的使用情况,踩坑篇里面包含了几个当时遇到的比较棘手的问题的解决思路,有兴趣的童鞋请关注。

本章完~

原文链接:http://tmq.qq.com/2016/08/java-code-coverage-tools-jacoco-principle/

<think>我们正在回答用户关于JaCoCo使用教程的问题。用户希望了解如何使用JaCoCo进行代码覆盖率测试。根据引用内容,我们可以整理出一个步骤指南。 引用[1]提到:JaCoCo是面向Java的开源代码覆盖率工具,以Java代理模式运行,在运行测试时检测字节码,并生成代码覆盖率报告。 引用[2]和[3]说明了代码覆盖率的意义:分析未覆盖代码以改进测试设计,检测废代码,提升代码质量。 引用[5]提供了具体的命令行操作步骤:包括dump生成exec文件,以及生成report报表。 因此,我们可以将教程分为以下几个部分: 1. JaCoCo简介 2. 代码覆盖率的意义 3. 使用JaCoCo的步骤(包括两种方式:与构建工具集成和命令行方式) 4. 查看报告 由于引用[5]提供了命令行方式的具体步骤,我们将重点放在命令行方式上,同时简要提及与构建工具(如Maven)的集成。 注意:用户可能使用不同的构建工具,但命令行方式具有通用性。 根据引用[5]: 生成exec文件的命令: java -jar jacococli.jar dump --address 127.0.0.1 --port 6300 --destfile jacoco-demo.exec 生成报告的命令: java -jar jacococli.jar report jacoco-demo.exec --classfiles D:\code\devops\SBD\target\classes --sourcefiles D:\code\devops\SBD\src\main\java --html html-report --xml report.xml --encoding utf-8 另外,引用[1]提到JaCoCoJava代理模式运行,所以我们需要先启动被检测的Java程序,并指定Java代理(jacocoagent)。 步骤: 1. 下载JaCoCo:从官网下载,包含jacocoagent.jar和jacococli.jar。 2. 启动被测程序时加入Java代理参数。 3. 运行测试(手动测试或自动测试)。 4. 转储exec文件(可以通过命令行或者关闭应用时自动生成)。 5. 生成报告。 下面开始组织回答。</think>### JaCoCo 使用教程:代码覆盖率测试指南 #### 一、JaCoCo 简介 JaCoCo 是面向 Java 的开源代码覆盖率工具,通过 **Java 代理模式**实时检测字节码,监控测试执行过程并生成覆盖率报告[^1]。它能精确统计: - 行覆盖率(Line Coverage) - 分支覆盖率(Branch Coverage) - 方法覆盖率(Method Coverage) - 指令级覆盖率(Instruction Coverage) #### 二、核心原理 JaCoCo 通过 **ASM 框架**在字节码执行时插入探针,利用 **JVM TI 接口**收集执行数据[^1]。其工作流程如下: 1. **插桩**:运行时修改字节码插入探针 2. **数据收集**:记录代码执行轨迹 3. **报告生成**:将原始数据(.exec)转换为可视化报告 #### 三、详细使用步骤 ##### 方式1:命令行操作(通用) 1. **启动被测程序**(附加 Java 代理): ```bash java -javaagent:jacocoagent.jar=includes=*,output=tcpserver,port=6300 -jar your-app.jar ``` - `includes=*`:监控所有类 - `output=tcpserver`:开启 TCP 服务端 - `port=6300`:指定监听端口[^5] 2. **执行测试用例**(手动/自动化测试) 3. **转储覆盖率数据**: ```bash java -jar jacococli.jar dump --address 127.0.0.1 --port=6300 --destfile coverage.exec ``` 4. **生成 HTML 报告**: ```bash java -jar jacococli.jar report coverage.exec \ --classfiles target/classes \ --sourcefiles src/main/java \ --html html-report \ --encoding utf-8 ``` - `--classfiles`:编译后的 .class 路径 - `--sourcefiles`:Java 源码路径[^5] ##### 方式2:Maven 集成(推荐) 1. 在 `pom.xml` 添加插件: ```xml <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.10</version> <executions> <execution> <goals> <goal>prepare-agent</goal> <!-- 启动代理 --> </goals> </execution> <execution> <id>report</id> <phase>test</phase> <goals> <goal>report</goal> <!-- 生成报告 --> </goals> </execution> </executions> </plugin> ``` 2. 执行测试并生成报告: ```bash mvn clean test ``` 报告路径:`target/site/jacoco/index.html` #### 四、报告解读技巧 示例报告指标: | 指标类型 | 覆盖率值 | 达标建议 | |----------------|----------|----------| | **行覆盖率** | 85% | >80% | | **分支覆盖率** | 70% | >75% | | **方法覆盖率** | 90% | >85% | 分析建议: 1. **红色行**:未覆盖代码 → 补充测试用例 2. **黄色分支**:条件未全覆盖 → 检查边界条件 3. **全绿文件**:测试充分 → 可降低维护优先级[^3] #### 五、最佳实践 1. **增量覆盖率**:聚焦新修改代码(引用[2]方案) 2. **持续集成**:与 Jenkins/GitLab CI 集成 3. **阈值控制**:在构建中设置覆盖率门禁 ```xml <!-- Maven 配置示例 --> <configuration> <rules> <rule> <limit> <!-- 低于85%行覆盖率则构建失败 --> <counter>LINE</counter> <value>COVEREDRATIO</value> <minimum>0.85</minimum> </limit> </rule> </rules> </configuration> ``` #### 六、常见问题解决 - **无数据问题**:检查代理是否加载(JVM 启动参数) - **源码错位**:确保 `--sourcefiles` 路径正确 - **依赖缺失**:报告需同时包含主代码和测试代码路径 > **代码覆盖率的意义**:不仅衡量测试完整性,更能通过未覆盖代码反推测试设计盲点,提升代码逻辑质量[^3]。但需注意:高覆盖率≠高质量,需结合其他测试手段。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值