
本文旨在解决在Sonarqube中Spring Boot应用使用JaCoCo和Maven进行代码覆盖率分析时,覆盖率始终显示0%的常见问题。核心在于JaCoCo和Surefire插件之间关于执行数据文件(.exec)和报告文件(.xml)路径及格式配置不一致。通过统一Maven pom.xml中的配置,确保JaCoCo代理正确生成数据,并将其转换为Sonarqube可识别的XML报告,即可实现正确的覆盖率展示。
1. 问题背景与现象分析
在使用Jenkins、Maven、JaCoCo和Sonarqube构建Spring Boot项目的CI/CD流水线时,一个常见的问题是Sonarqube上代码覆盖率始终显示为0%。这通常伴随着Maven构建日志中出现类似 [INFO] Skipping JaCoCo execution due to missing execution data file. 的警告信息。尽管单元测试已成功运行,但JaCoCo未能正确生成或找到其执行数据文件(通常是.exec文件),或者生成的报告文件(.xml)路径与Sonarqube期望的路径不符。
导致此问题的根本原因通常是JaCoCo Maven插件和Maven Surefire插件之间的配置不一致,特别是在以下几个方面:
- JaCoCo代理数据文件路径不一致: JaCoCo prepare-agent 目标生成.exec文件的位置与JaCoCo report 目标期望读取的位置不一致。
- Surefire插件未传递JaCoCo代理参数: Surefire插件在执行测试时,未能将JaCoCo代理所需的JVM参数传递给JVM。
- JaCoCo XML报告路径不一致: JaCoCo report 目标生成XML报告的路径与Sonarqube扫描器通过 sonar.coverage.jacoco.xmlReportPaths 属性配置的路径不一致。
2. 解决方案:统一Maven pom.xml 配置
解决此问题的关键在于确保所有相关插件和属性在 pom.xml 中保持高度一致性。
2.1 核心Maven pom.xml 属性配置
首先,在 pom.xml 的 <properties> 块中,定义Sonarqube扫描器所需的报告路径。这些路径将指导Sonarqube在哪里查找单元测试报告和JaCoCo生成的代码覆盖率XML报告。
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.0</maven-jar-plugin.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- SonarQube 单元测试报告路径 -->
<sonar.surefire.reportsPath>${basedir}/target/surefire-reports</sonar.surefire.reportsPath>
<!-- SonarQube JaCoCo XML覆盖率报告路径 -->
<sonar.coverage.jacoco.xmlReportPaths>${basedir}/target/jacoco_report/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
</properties>注意事项:
- sonar.coverage.jacoco.xmlReportPaths 必须指向JaCoCo最终生成的XML报告文件,而不是其二进制.exec文件。
- 路径应使用绝对路径或基于项目根目录的相对路径。
2.2 JaCoCo Maven 插件配置
JaCoCo插件负责在测试运行期间收集代码覆盖率数据,并将其转换为XML报告。其配置通常包含两个主要执行(execution):prepare-agent 和 report。
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.6</version> <!-- 建议使用最新稳定版本 -->
<executions>
<!-- 1. prepare-agent: 在测试执行前准备JaCoCo代理 -->
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<!-- 指定JaCoCo代理生成的二进制执行数据文件路径 -->
<destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile>
<!-- 将JaCoCo代理参数传递给Maven Surefire插件 -->
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
<!-- 2. report: 在测试执行后生成XML报告 -->
<execution>
<id>report</id>
<phase>test</phase> <!-- 绑定到test阶段,确保在单元测试后执行 -->
<goals>
<goal>report</goal>
</goals>
<configuration>
<!-- 指定要读取的二进制执行数据文件,必须与prepare-agent的destFile一致 -->
<dataFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</dataFile>
<!-- 指定XML报告的输出目录 -->
<outputDirectory>${project.build.directory}/jacoco_report</outputDirectory>
<!-- 确保生成的报告名为jacoco.xml,与sonar.coverage.jacoco.xmlReportPaths一致 -->
<outputFileNames>jacoco.xml</outputFileNames>
</configuration>
</execution>
</executions>
</plugin>注意事项:
- <destFile> 在 prepare-agent 中定义了JaCoCo代理生成.exec文件的位置。
- <dataFile> 在 report 中定义了JaCoCo报告生成器读取.exec文件的位置。这两个路径必须完全一致。
- <outputDirectory> 在 report 中定义了XML报告的输出目录。结合 <outputFileNames>jacoco.xml</outputFileNames>,确保最终报告文件为 target/jacoco_report/jacoco.xml,这与 sonar.coverage.jacoco.xmlReportPaths 的配置相匹配。
- propertyName surefireArgLine 是为了将JaCoCo代理参数传递给Surefire插件。
2.3 Maven Surefire 插件配置
Maven Surefire插件负责执行单元测试。它需要配置以接收并应用JaCoCo代理传递的JVM参数。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version> <!-- 建议使用最新稳定版本 -->
<configuration>
<!-- 将JaCoCo代理参数传递给JVM -->
<argLine>${surefireArgLine}</argLine>
<!-- 指定Surefire报告的输出目录,与sonar.surefire.reportsPath一致 -->
<reportsDirectory>${sonar.surefire.reportsPath}</reportsDirectory>
</configuration>
</plugin>注意事项:
- <argLine>${surefireArgLine}</argLine> 是关键,它确保JaCoCo代理在测试执行时被激活并收集数据。
- <reportsDirectory> 应该与 sonar.surefire.reportsPath 保持一致。
3. Jenkins 流水线配置
在Jenkins流水线中,需要确保Maven构建命令正确执行了JaCoCo的 prepare-agent 和 report 目标,并且Sonarqube扫描器能够找到生成的JaCoCo XML报告。
pipeline {
agent any
stages {
stage('Build and Test') {
steps {
// 清理、编译、运行测试并生成JaCoCo报告
// `mvn clean verify` 会触发 prepare-agent (在validate阶段), test (运行测试), report (在test阶段)
sh 'mvn clean verify'
// 或者,如果report目标绑定到test阶段,`mvn clean test` 也可以
// sh 'mvn clean test'
}
}
stage('SonarQube Analysis') {
steps {
// SonarQube扫描器将自动读取pom.xml中定义的sonar.*属性
// 确保不要在命令行中覆盖pom.xml中的sonar.coverage.jacoco.xmlReportPaths
withSonarQubeEnv('Your SonarQube Server') { // 'Your SonarQube Server' 是Jenkins中配置的SonarQube服务器名称
sh 'mvn sonar:sonar'
// 如果pom.xml中未定义sonar.coverage.jacoco.xmlReportPaths,则可以在此处指定
// sh 'mvn sonar:sonar -Dsonar.coverage.jacoco.xmlReportPaths=target/jacoco_report/jacoco.xml'
}
}
}
}
}注意事项:
- mvn clean verify 命令通常比 mvn clean test 更为完整,因为它会执行Maven的整个生命周期,包括 prepare-agent (通常绑定到 validate 阶段) 和 report (绑定到 test 或 verify 阶段)。
- withSonarQubeEnv 步骤确保SonarQube环境变量被正确设置。
- 如果 pom.xml 中已正确配置 sonar.coverage.jacoco.xmlReportPaths,则 mvn sonar:sonar 命令会自动读取该属性,无需在命令行中重复 -D 参数,以避免潜在的冲突。
4. 验证与故障排除
完成上述配置后,执行Jenkins流水线。
- 检查Maven构建日志: 确保没有 Skipping JaCoCo execution due to missing execution data file 警告。
-
检查项目 target 目录:
- 在 target/coverage-reports/ 目录下,应该能找到 jacoco-ut.exec 文件。
- 在 target/jacoco_report/ 目录下,应该能找到 jacoco.xml 文件。
- 在 target/surefire-reports/ 目录下,应该能找到单元测试的XML报告。
- 检查Sonarqube分析日志: 在Jenkins的SonarQube分析步骤中,查看日志输出,确认Sonarqube扫描器是否成功读取了JaCoCo XML报告。日志中应包含类似 INFO: Sensor JaCoCo XML Report Sensor [jacoco] (done) ... 的信息,并且会列出它处理的XML报告路径。
- 查看Sonarqube界面: 登录Sonarqube,检查项目的代码覆盖率是否已正确显示。
如果仍然遇到问题,请仔细核对所有路径和文件名是否完全一致,并确保Maven插件的版本兼容。
5. 总结
在Sonarqube中实现JaCoCo代码覆盖率的正确显示,核心在于JaCoCo、Surefire插件以及Sonarqube扫描器之间关于报告文件路径和格式的配置一致性。通过在Maven pom.xml 中统一 <properties> 和插件配置,特别是确保 .exec 文件的生成和读取路径一致,以及 .xml 报告的输出路径与Sonarqube期望的路径匹配,可以有效解决代码覆盖率为0%的问题。遵循本教程的步骤,将有助于构建一个健壮且准确的代码质量分析流水线。










