集成测试报告路径异常及Maven Failsafe插件执行失败排查
问题现象
- 单元测试报告正常生成在
/target/surefire-report/junitreports,但集成测试执行后报告也存于该路径 /target/failsafe-reports已创建,但出现被测类ClassNotFoundException,最终导致maven-failsafe-plugin:3.2.1:verify执行失败- Jenkins执行命令:
mvn verify --also-make --no-transfer-progress -Dgroups=integration -Pintegration-test -T1C
- 集成测试类使用TestNG的
@Test(groups="integration")注解 - 当前插件配置:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.2.1</version> <configuration> <includes> <include>**/*Test.java</include> </includes> <excludes> <exclude>**/IntegrationTest.java</exclude> </excludes> </configuration> </plugin> </plugins> </build> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>3.2.1</version> <executions> <execution> <id>integration-tests</id> <phase>verify</phase> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> <configuration> <groups>integration</groups> <skip>{maven.failsafe.plugin.skip}</skip> <includes> <include>**/*IntegrationTest.java</include> </includes> <argLine>{jacoco.argLine}</argLine> <reportsDirectory>target/failsafe-reports</reportsDirectory> <properties> <property> <name>listener</name> <value>org.sonar.java.jacoco.JUnitListener</value> </property> </properties> </configuration> </plugin> </plugins> </build>
核心问题点
1. Surefire插件排除规则错误,集成测试被重复执行
当前Surefire的exclude配置为**/IntegrationTest.java,仅会排除**文件名恰好为IntegrationTest.java**的类,但你的集成测试类是*IntegrationTest.java结尾(比如UserIntegrationTest.java),这类类仍会被Surefire执行,因此报告被写入Surefire的路径。
2. 重复的<build>块引发配置冲突
你将Surefire和Failsafe分别放在两个独立的<build>块中,Maven对重复的build配置会进行合并,但可能导致Failsafe的部分配置被覆盖或未正确加载,进而影响报告路径的生效和插件执行逻辑。
3. Maven变量引用缺失$符号,参数解析失败
配置中的<skip>{maven.failsafe.plugin.skip}</skip>和<argLine>{jacoco.argLine}</argLine>均缺少$符号,正确的变量引用应为${maven.failsafe.plugin.skip}和${jacoco.argLine}。变量解析失败会导致Jacoco参数无法正确传递,或跳过逻辑异常,间接引发类加载问题。
4. Failsafe执行阶段配置错误,破坏生命周期顺序
Failsafe插件的integration-test目标默认绑定到Maven生命周期的integration-test阶段,verify目标默认绑定到verify阶段。你将整个execution的phase设为verify,会导致两个目标都在verify阶段执行,此时被测类的编译输出可能未被正确纳入类路径,从而触发ClassNotFoundException。
5. Jacoco监听器依赖缺失导致类加载异常
配置中使用的org.sonar.java.jacoco.JUnitListener是SonarQube的Jacoco监听器,若该依赖未在测试类路径中正确引入,会导致监听器初始化失败,进而引发类加载异常。
修复方案
- 合并
<build>块,将Surefire和Failsafe放在同一个<build><plugins>下:
<build> <plugins> <!-- Surefire插件配置 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.2.1</version> <configuration> <includes> <include>**/*Test.java</include> </includes> <excludes> <exclude>**/*IntegrationTest.java</exclude> </excludes> </configuration> </plugin> <!-- Failsafe插件配置 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>3.2.1</version> <executions> <execution> <id>integration-tests</id> <phase>integration-test</phase> <goals> <goal>integration-test</goal> </goals> </execution> <execution> <id>verify-integration-tests</id> <phase>verify</phase> <goals> <goal>verify</goal> </goals> </execution> </executions> <configuration> <groups>integration</groups> <skip>${maven.failsafe.plugin.skip}</skip> <includes> <include>**/*IntegrationTest.java</include> </includes> <argLine>${jacoco.argLine}</argLine> <reportsDirectory>target/failsafe-reports</reportsDirectory> <properties> <property> <name>listener</name> <value>org.sonar.java.jacoco.JUnitListener</value> </property> </properties> </configuration> </plugin> </plugins> </build>
修正Surefire的exclude规则,改为
**/*IntegrationTest.java,确保所有集成测试类被排除在单元测试之外。补全变量引用的
$符号,确保Maven能正确解析配置参数。拆分Failsafe的执行阶段,将
integration-test目标绑定到integration-test阶段,verify目标绑定到verify阶段,遵循Maven生命周期顺序。添加Jacoco监听器依赖,确保Sonar相关Jacoco包存在于测试类路径:
<dependency> <groupId>org.sonarsource.sonar.java</groupId> <artifactId>sonar-java-jacoco</artifactId> <version>7.30.0.34429</version> <!-- 使用与Sonar版本匹配的版本 --> <scope>test</scope> </dependency>
内容的提问来源于stack exchange,提问作者ravi saurav

