1. 概述
本教程将展示当JaCoCo代码覆盖率低于特定阈值时,如何导致Maven构建失败。首先我们来看不带任何阈值的基础JaCoCo插件配置,然后添加一个新的执行目标来专门检查覆盖率。
我们将重点介绍这个新执行目标的关键元素。接着扩展一个简单的ProductService示例,观察添加BRANCH(分支)和INSTRUCTION(指令)覆盖规则后的效果。最后总结使用JaCoCo强制执行规则对质量控制的好处。
2. JaCoCo Maven插件
先以最简单形式使用JaCoCo插件。这意味着在执行mvn clean install时,插件会计算代码覆盖率并生成报告:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<configuration>
<excludes>
<exclude>com/baeldung/**/ExcludedPOJO.class</exclude>
<exclude>com/baeldung/**/*DTO.*</exclude>
<exclude>**/config/*</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-site</id>
<phase>package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
3. 示例设置
接下来创建两个简单服务:CustomerService和ProductService。在ProductService中添加*getSalePrice()*方法,该方法包含两个分支(flag为true/false):
public double getSalePrice(double originalPrice, boolean flag) {
double discount;
if (flag) {
discount = originalPrice - originalPrice * DISCOUNT;
} else {
discount = originalPrice;
}
return discount;
}
编写两个测试用例覆盖两种条件:
@Test
public void givenOriginalPrice_whenGetSalePriceWithFlagTrue_thenReturnsDiscountedPrice() {
ProductService productService = new ProductService();
double salePrice = productService.getSalePrice(100, true);
assertEquals(salePrice, 75);
}
@Test
public void givenOriginalPrice_whenGetSalePriceWithFlagFalse_thenReturnsDiscountedPrice() {
ProductService productService = new ProductService();
double salePrice = productService.getSalePrice(100, false);
assertEquals(salePrice, 100);
}
类似地,CustomerService包含简单方法*getCustomerName()*:
public String getCustomerName() {
return "some name";
}
对应的单元测试:
@Test
public void givenCustomer_whenGetCustomer_thenReturnNewCustomer() {
CustomerService customerService = new CustomerService();
assertNotNull(customerService.getCustomerName());
}
4. 使用JaCoCo设置测试覆盖率基线
基础类和测试就绪后,先执行mvn clean install观察JaCoCo报告结果,建立当前模块测试覆盖率的基线:
模块构建成功。查看JaCoCo报告:
当前覆盖率为72%,Maven构建成功。
5. 向JaCoCo插件添加规则
**现在添加规则:要求指令覆盖率不低于70%,分支覆盖率不低于68%**。在插件中定义新执行目标:
<execution>
<id>check-coverage</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>INSTRUCTION</counter>
<value>COVEREDRATIO</value>
<minimum>0.70</minimum>
</limit>
<limit>
<counter>BRANCH</counter>
<value>COVEREDRATIO</value>
<minimum>0.68</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
关键点说明:
5.1. JaCoCo中的**
*
- ✅ BUNDLE:整个代码库的聚合覆盖率(示例中使用)
- ✅ CLASS:类级别
- ✅ LINE:代码行级别
- ✅ METHOD:方法级别
- ✅ PACKAGE:包级别
BUNDLE级别提供项目整体覆盖率视图,适合设置最高级别的覆盖规则。
5.2. JaCoCo中的**
定义一个或多个限制条件,每个*
- *
*:计数器类型(如INSTRUCTION) - *
*:度量方式(如COVEREDRATIO) - *
*:最小阈值
常用度量方式:
- ✅ COVEREDRATIO:覆盖比例(示例使用)
- ❌ COVEREDCOUNT:已覆盖数量
- ❌ MISSEDCOUNT:未覆盖数量
- ❌ TOTALCOUNT:总数量
5.3. JaCoCo中的**
计数器类型决定覆盖率的计算维度:
- ✅ INSTRUCTION:指令覆盖率(字节码指令)
- ✅ BRANCH:分支覆盖率(if/switch等决策点)
- ✅ LINE:代码行覆盖率
- ❌ COMPLEXITY:圈复杂度
- ❌ METHOD:方法覆盖率
- ❌ CLASS:类覆盖率
核心计数器对比: | 计数器 | 作用 | 重要性 | |--------|------|--------| | INSTRUCTION | 衡量代码执行程度 | ⭐⭐⭐⭐ | | BRANCH | 确保true/false分支都被测试 | ⭐⭐⭐⭐ | | LINE | 精确到代码行 | ⭐⭐⭐ |
6. 覆盖率下降导致构建失败
为触发构建失败,禁用以下测试:
@Test
@Disabled
public void givenOriginalPrice_whenGetSalePriceWithFlagFalse_thenReturnsDiscountedPrice() {//...}
再次执行mvn clean install:
构建失败,错误信息:
[ERROR] Failed to execute goal org.jacoco:jacoco-maven-plugin:0.8.6:check (check-coverage) on project testing-libraries-2: Coverage checks have not been met.
失败原因分析:
- 指令覆盖率降至68%(要求≥70%)
- 分支覆盖率降至50%(要求≥68%)
要修复构建,需恢复测试使覆盖率达标。
7. 结论
本文展示了如何通过JaCoCo在代码覆盖率低于阈值时使Maven构建失败。关键点包括:
✅ 强制执行覆盖率规则:
- 确保代码库始终满足最低测试覆盖要求
- 阻止低覆盖率代码进入后续开发阶段
✅ 多维度覆盖控制:
- 指令覆盖率反映代码执行程度
- 分支覆盖率确保决策点测试完整
✅ 质量保障机制:
- 识别测试不足区域
- 降低低质量代码发布风险
⚠️ 实施建议:
- 从适中阈值开始(如70%)
- 逐步提高要求
- 结合代码审查使用
源码可在GitHub获取