升级依赖库后代码覆盖率下降,Jacoco排除规则失效求助
问题概述
升级项目依赖至Gradle 7.2、Spring Boot 2.7.13、JUnit 4.13后,未做功能变更或新增类,但代码覆盖率从84%降至49%。排查Jacoco报告发现,使用@RunWith(MockitoJUnitRunner.class)的测试类覆盖率为0,尝试@InjectMocks注解、排除对应类、添加@Tag("ignoreaccept")标记均未解决问题。
涉及代码与配置
测试类(com/**/accept包下)
@RunWith(MockitoJUnitRunner.class) public class AbstractProcTest { private LSD ls = new LSD(); private AbstractProc processor = new SmallProc(ls); @Mock private RestClient restClient; }
build.gradle测试配置
test { useJUnitPlatform { excludeTags "ignoreaccept" } finalizedBy jacocoTestReport }
Jacoco配置
jacocoTestCoverageVerification { violationRules { rule { element = 'BUNDLE' excludes = ['**/com/vk/isr/kvr/accept/**/*'] limit { minimum = 0.84 } } } } jacocoTestReport { group 'documentation' reports { xml.enabled true csv.enabled false html.destination file("${buildDir}/result/report") } } jacocoTestCoverageVerification.mustRunAfter jacocoTestReport check.dependsOn jacocoTestReport check.dependsOn jacocoTestCoverageVerification compileJava.dependsOn(processResources)
问题原因分析
- JUnit平台兼容性问题:Gradle 7+的
useJUnitPlatform默认仅支持JUnit 5测试,JUnit 4的@RunWith测试若未配置JUnit Vintage引擎,会导致测试未被执行,对应生产类的代码覆盖率无法被统计,同时未执行的测试不会标记生产类为已覆盖,拉低整体覆盖率。 - 排除规则未生效:
- 测试类的
@Tag标记可能未被正确识别,或排除路径有误,导致测试仍被执行但无有效覆盖; - Jacoco的
excludes规则仅排除指定路径的生产类覆盖率统计,若当前排除的是测试类路径而非对应生产类,无法解决未覆盖问题。
- 测试类的
- Mockito注解使用不当:测试类中
@Mock的restClient未注入到processor,且无实际@Test方法,测试未执行任何业务逻辑,导致覆盖率为0。
解决方案
方案1:让JUnit4测试正常执行(保留测试并统计覆盖率)
步骤1:添加JUnit Vintage引擎依赖
在build.gradle中添加依赖,让JUnit平台支持JUnit4测试:
dependencies { // 其他依赖... testImplementation 'org.junit.vintage:junit-vintage-engine:5.9.2' testImplementation 'org.mockito:mockito-junit-jupiter:4.11.0' }
步骤2:修正Mockito注解与添加测试方法
确保依赖注入生效,并添加实际测试逻辑:
@RunWith(MockitoJUnitRunner.class) public class AbstractProcTest { private LSD ls = new LSD(); @InjectMocks private AbstractProc processor = new SmallProc(ls); @Mock private RestClient restClient; // 添加实际测试方法 @Test public void testProcessorExecute() { // 模拟RestClient行为 when(restClient.callApi(anyString())).thenReturn("mockResult"); // 执行处理器逻辑 processor.execute(); // 验证交互 verify(restClient, times(1)).callApi(anyString()); } }
方案2:完全忽略相关测试与对应生产类(跳过测试且不统计覆盖率)
步骤1:正确跳过测试类
修改test任务配置,直接排除测试包,确保测试不被执行:
test { useJUnitPlatform { excludeTags "ignoreaccept" // 直接排除accept包下的所有测试类 exclude '**/accept/**' } finalizedBy jacocoTestReport }
步骤2:修正Jacoco排除规则
将测试对应的生产类加入排除列表,确保这些类的覆盖率不被纳入统计:
jacocoTestCoverageVerification { violationRules { rule { element = 'BUNDLE' excludes = [ '**/com/vk/isr/kvr/accept/**/*', // 添加对应的生产类路径,示例如下 '**/com/vk/isr/kvr/xxx/AbstractProc*', '**/com/vk/isr/kvr/xxx/SmallProc*', '**/com/vk/isr/kvr/xxx/LSD*' ] limit { minimum = 0.84 } } } }
方案3:迁移至JUnit5(长期最优解)
将JUnit4测试迁移为JUnit5格式,适配Gradle 7+的JUnit平台:
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) public class AbstractProcTest { private LSD ls = new LSD(); @InjectMocks private AbstractProc processor = new SmallProc(ls); @Mock private RestClient restClient; @Test public void testProcessorExecute() { // 测试逻辑同前 } }
内容的提问来源于stack exchange,提问作者KVL
相关产品推荐
相关产品推荐

