Quarkus多模块Jacoco覆盖率异常:API测试在Impl模块时覆盖率为0
问题:Quarkus多模块项目中跨模块测试无法统计API模块覆盖率
我的Quarkus应用包含module-api和module-impl两个模块,所有单元测试都放在module-impl里。执行mvn verify后,覆盖率报告只统计了module-impl的代码覆盖率,module-api的覆盖率显示为0%——但明明已经写了对应测试。把API模块的测试移到module-api里后,就能得到正确的覆盖率结果。为什么把所有测试放在单个模块时就不行?我已经按照官方指南配置了。
项目结构
|- pom.xml (root) | |-- module-api |--- src |---- main |--- pom.xml | |-- module-impl |--- src |---- main |---- test |--- pom.xml
pom.xml (root)
<?xml version="1.0"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>jacoco-demo4</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>module-api</module> <module>module-impl</module> </modules> <properties> <compiler-plugin.version>3.10.1</compiler-plugin.version> <maven.compiler.release>11</maven.compiler.release> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id> <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id> <quarkus.platform.version>2.15.3.Final</quarkus.platform.version> <skipITs>true</skipITs> <surefire-plugin.version>3.0.0-M7</surefire-plugin.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>${quarkus.platform.group-id}</groupId> <artifactId>${quarkus.platform.artifact-id}</artifactId> <version>${quarkus.platform.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-jacoco</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-arc</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-junit5</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>${quarkus.platform.group-id}</groupId> <artifactId>quarkus-maven-plugin</artifactId> <version>${quarkus.platform.version}</version> <extensions>true</extensions> <executions> <execution> <goals> <goal>build</goal> <goal>generate-code</goal> <goal>generate-code-tests</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>${compiler-plugin.version}</version> <configuration> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>${surefire-plugin.version}</version> <configuration> <systemPropertyVariables> <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> <maven.home>${maven.home}</maven.home> </systemPropertyVariables> </configuration> </plugin> <plugin> <artifactId>maven-failsafe-plugin</artifactId> <version>${surefire-plugin.version}</version> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> <configuration> <systemPropertyVariables> <native.image.path>${project.build.directory}/${project.build.finalName}-runner </native.image.path> <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> <maven.home>${maven.home}</maven.home> </systemPropertyVariables> </configuration> </execution> </executions> </plugin> </plugins> </build> <profiles> <profile> <id>native</id> <activation> <property> <name>native</name> </property> </activation> <properties> <skipITs>false</skipITs> <quarkus.package.type>native</quarkus.package.type> </properties> </profile> </profiles> </project>
pom.xml (module-api)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>jacoco-demo4</artifactId> <groupId>com.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>module-api</artifactId> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> </project>
pom.xml (module-impl)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>jacoco-demo4</artifactId> <groupId>com.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>module-impl</artifactId> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>com.example</groupId> <artifactId>module-api</artifactId> <version>${project.version}</version> <scope>compile</scope> </dependency> </dependencies> </project>
解答
这是因为Quarkus集成的Jacoco默认只统计当前测试模块的代码覆盖率,不会自动包含依赖模块的代码。当你在module-impl里写测试调用module-api的代码时,module-api的字节码是作为依赖被引入的,没有被Jacoco的探针插桩,所以无法统计到执行情况。
要解决这个问题,需要调整Jacoco的配置,让它在构建module-api时就插入覆盖率探针,并且在module-impl执行测试时收集这些探针的数据。具体步骤如下:
- 在
module-api的pom.xml中添加Jacoco插件配置,确保构建时生成带探针的字节码:
<build> <plugins> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <executions> <execution> <goals> <goal>prepare-agent</goal> </goals> </execution> <execution> <id>report</id> <phase>verify</phase> <goals> <goal>report</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
- 在根pom.xml中配置Jacoco的聚合报告,把多个模块的覆盖率数据合并:
<build> <plugins> <!-- 其他插件保持不变,新增Jacoco聚合配置 --> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.8</version> <!-- 版本可根据Quarkus兼容情况调整 --> <executions> <execution> <id>report-aggregate</id> <phase>verify</phase> <goals> <goal>report-aggregate</goal> </goals> <configuration> <dataFileIncludes> <dataFileInclude>**/jacoco.exec</dataFileInclude> </dataFileIncludes> <outputDirectory>${project.reporting.outputDirectory}/jacoco-aggregate</outputDirectory> </configuration> </execution> </executions> </plugin> </plugins> </build>
- 确保
module-impl的测试能访问到module-api的插桩字节码:
因为module-api已经配置了prepare-agent,构建时会生成带探针的class文件,module-impl依赖的是这个带探针的版本,测试执行时Jacoco会收集module-api的执行数据。
执行mvn clean verify后,根目录的target/site/jacoco-aggregate下就能看到包含module-api和module-impl的完整覆盖率报告了。
另外需要注意:如果module-api是纯接口模块,没有可执行代码,那覆盖率本来就是0;但如果有抽象类或默认方法,就需要上述配置才能统计到测试对这些代码的调用情况。
内容的提问来源于stack exchange,提问作者XuBo
相关产品推荐
相关产品推荐

