Maven插件【测试覆盖率】:jacoco-maven-plugin

12/31/2025 后端开发构建工具Maven

目录


参考


# Maven插件【测试覆盖率】:jacoco-maven-plugin

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>${jacoco.version}</version>
    <configuration>
        <skip>${jacoco.skip}</skip>
        <dataFile>${project.build.directory}/jacoco.exec</dataFile>
    </configuration>
    <executions>
        <execution>
            <id>default-instrument</id>
            <goals>
                <goal>instrument</goal>
            </goals>
        </execution>
        <execution>
            <id>default-restore-instrumented-classes</id>
            <goals>
                <goal>restore-instrumented-classes</goal>
            </goals>
            <configuration>
                <!--                            <excludes>com/github/dreamhead/moco/*</excludes>-->
            </configuration>
        </execution>
        <execution>
            <id>default-report</id>
            <goals>
                <goal>report</goal>
            </goals>
        </execution>
    </executions>
</plugin>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# JaCoCo Maven插件配置解析

这个配置是用于jacoco-maven-plugin插件的配置,该插件是用于Java代码覆盖率分析的Maven插件。下面我将详细解析这个配置的作用、插件功能以及常见使用方式。

# 插件概述

jacoco-maven-plugin是JaCoCo(Java Code Coverage)工具的Maven集成插件,用于测量Java代码的测试覆盖率。JaCoCo通过字节码插桩技术,在运行时收集代码执行信息,生成详细的覆盖率报告,包括行覆盖率、分支覆盖率、方法覆盖率等指标。

# 配置解析

# 基本配置部分

<configuration>
    <skip>${jacoco.skip}</skip>
    <dataFile>${project.build.directory}/jacoco.exec</dataFile>
</configuration>
1
2
3
4
  • skip: 控制是否跳过JaCoCo的执行,值来自Maven属性${jacoco.skip},通常用于在特定情况下禁用覆盖率分析
  • dataFile: 指定覆盖率数据文件的存储路径,默认为target/jacoco.exec

# 执行(executions)部分

配置中定义了三个执行目标:

  1. instrument目标:

    <execution>
        <id>default-instrument</id>
        <goals>
            <goal>instrument</goal>
        </goals>
    </execution>
    
    1
    2
    3
    4
    5
    6
    • 对字节码进行插桩,插入额外的指令用于跟踪代码执行情况
    • 这是JaCoCo实现覆盖率分析的核心步骤
  2. restore-instrumented-classes目标:

    <execution>
        <id>default-restore-instrumented-classes</id>
        <goals>
            <goal>restore-instrumented-classes</goal>
        </goals>
    </execution>
    
    1
    2
    3
    4
    5
    6
    • 恢复被插桩的类文件到原始状态
    • 注释掉的excludes配置可用于排除特定包或类不参与覆盖率分析
  3. report目标:

    <execution>
        <id>default-report</id>
        <goals>
            <goal>report</goal>
        </goals>
    </execution>
    
    1
    2
    3
    4
    5
    6
    • 生成覆盖率报告,默认生成HTML格式报告
    • 报告会基于.exec文件中的数据,结合源代码和编译后的字节码生成

# 插件的主要功能

  1. prepare-agent: 配置JVM代理以收集覆盖率数据(此配置中未显式出现,但常用)
  2. instrument: 对字节码进行插桩处理
  3. restore-instrumented-classes: 恢复原始类文件
  4. report: 生成可视化覆盖率报告
  5. check: 检查覆盖率是否达到阈值(此配置中未使用)
  6. merge: 合并多个覆盖率数据文件
  7. dump: 请求远程JVM的覆盖率数据转储

# 典型使用场景

# 1. 基本使用流程

  1. 将插件配置添加到项目的pom.xml
  2. 运行测试: mvn clean test - 这会自动执行插桩并收集覆盖率数据
  3. 生成报告: mvn verify - 这会触发report目标生成报告
  4. 查看报告: 在target/site/jacoco目录下查看HTML报告

# 2. 多模块项目

对于多模块项目,可以在父POM中使用report-aggregate目标合并各子模块的覆盖率数据:

<execution>
    <id>report-aggregate</id>
    <goals>
        <goal>report-aggregate</goal>
    </goals>
</execution>
1
2
3
4
5
6

# 3. 设置覆盖率阈值

可以配置check目标来设置最低覆盖率要求,未达标时构建失败:

<execution>
    <id>check</id>
    <goals>
        <goal>check</goal>
    </goals>
    <configuration>
        <rules>
            <rule>
                <element>BUNDLE</element>
                <limits>
                    <limit>
                        <counter>LINE</counter>
                        <value>COVEREDRATIO</value>
                        <minimum>0.80</minimum>
                    </limit>
                </limits>
            </rule>
        </rules>
    </configuration>
</execution>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 4. 排除特定类/包

可以通过excludes配置排除不需要分析覆盖率的代码:

<configuration>
    <excludes>
        <exclude>com/example/legacy/**</exclude>
    </excludes>
</configuration>
1
2
3
4
5

# 高级用法

  1. 与CI/CD集成: 可以将JaCoCo与Jenkins等CI工具集成,实现自动化覆盖率检查和报告
  2. 分离单元测试和集成测试覆盖率: 可以为不同类型的测试生成独立的覆盖率报告
  3. 命令行工具: 除了Maven插件,JaCoCo还提供CLI工具(jacococli.jar)用于非Maven项目

# 注意事项

  1. JaCoCo需要与测试框架(如JUnit)和测试执行插件(如maven-surefire-plugin)配合使用
  2. 插桩可以在编译时(offline)或运行时(on-the-fly)进行,Maven插件通常使用后者
  3. 对于大型项目,可能需要调整JVM内存设置以确保覆盖率分析顺利进行

通过合理配置jacoco-maven-plugin,开发者可以有效地监控测试覆盖率,提高代码质量,并集成到自动化构建流程中。


# JaCoCo插件在多模块项目中如何配置才能正确统计整体覆盖率?

# JaCoCo在多模块项目中配置整体覆盖率统计的完整指南

JaCoCo(Java Code Coverage)是Java项目中广泛使用的代码覆盖率工具,在多模块项目中正确配置JaCoCo以实现整体覆盖率统计需要特别注意一些关键点。下面我将详细介绍多模块项目中JaCoCo的配置方法和最佳实践。

# 一、基础配置:父模块设置

在多模块项目中,首先应该在父模块的pom.xml中进行JaCoCo的基础配置,确保所有子模块能够继承这些配置。

<!-- 父模块pom.xml中的配置 -->
<properties>
    <jacoco.version>0.8.10</jacoco.version>
</properties>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco.version}</version>
                <executions>
                    <execution>
                        <id>prepare-agent</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

这段配置做了以下工作:

  1. 定义了JaCoCo的版本属性
  2. 在pluginManagement中配置了jacoco-maven-plugin
  3. 设置了prepare-agent目标,用于在测试运行时收集覆盖率数据

# 二、子模块配置

每个需要统计覆盖率的子模块需要在pom.xml中引入JaCoCo插件:

<!-- 子模块pom.xml中的配置 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
1
2
3
4
5
6
7
8
9

# 三、聚合报告配置

为了生成整个项目的汇总覆盖率报告,需要在父模块或专门的聚合模块中添加report-aggregate目标配置:

<!-- 父模块或聚合模块pom.xml中的配置 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <executions>
                <execution>
                    <id>report-aggregate</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>report-aggregate</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

report-aggregate目标会收集所有子模块的覆盖率数据(.exec文件)并生成一个汇总报告。

# 四、完整配置示例

一个完整的父模块配置可能如下所示:

<build>
    <plugins>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>${jacoco.version}</version>
            <executions>
                <execution>
                    <id>prepare-agent</id>
                    <goals>
                        <goal>prepare-agent</goal>
                    </goals>
                </execution>
                <execution>
                    <id>report</id>
                    <phase>test</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                </execution>
                <execution>
                    <id>report-aggregate</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>report-aggregate</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 五、执行命令

配置完成后,可以通过以下命令生成覆盖率报告:

  1. 生成各子模块独立报告

    mvn clean test
    
    1

    各子模块的报告会生成在target/site/jacoco/index.html

  2. 生成聚合报告

    mvn clean verify
    
    1

    聚合报告会生成在父模块的target/site/jacoco-aggregate/index.html

# 六、高级配置选项

# 1. 设置覆盖率阈值

可以配置check目标来设置最低覆盖率要求:

<execution>
    <id>check</id>
    <goals>
        <goal>check</goal>
    </goals>
    <configuration>
        <rules>
            <rule>
                <element>BUNDLE</element>
                <limits>
                    <limit>
                        <counter>LINE</counter>
                        <value>COVEREDRATIO</value>
                        <minimum>0.80</minimum>
                    </limit>
                </limits>
            </rule>
        </rules>
    </configuration>
</execution>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 2. 排除特定类或包

可以通过excludes配置排除不需要分析覆盖率的代码:

<configuration>
    <excludes>
        <exclude>**/generated/**</exclude>
        <exclude>**/model/*</exclude>
    </excludes>
</configuration>
1
2
3
4
5
6

# 3. 合并规则配置

对于多模块项目,可能需要更详细的合并配置:

<execution>
    <id>merge-results</id>
    <phase>verify</phase>
    <goals>
        <goal>merge</goal>
    </goals>
    <configuration>
        <fileSets>
            <fileSet>
                <directory>module-a/target</directory>
                <includes>
                    <include>*.exec</include>
                </includes>
            </fileSet>
            <fileSet>
                <directory>module-b/target</directory>
                <includes>
                    <include>*.exec</include>
                </includes>
            </fileSet>
        </fileSets>
    </configuration>
</execution>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 七、常见问题与解决方案

  1. 报告为空:检查测试是否实际执行,确保测试覆盖了目标代码
  2. 无法生成汇总报告:检查各子模块的target目录中是否存在.exec文件,确认合并配置正确
  3. 版本冲突:统一在父模块中定义JaCoCo插件版本,避免子模块使用不同版本
  4. 路径问题:在多模块项目中,特别注意文件路径的配置,确保能正确找到各模块的.exec文件

# 八、与CI/CD集成

JaCoCo可以轻松集成到CI/CD流程中:

  1. 在Jenkins等CI工具中配置JaCoCo报告收集
  2. 设置覆盖率阈值作为质量门禁
  3. 将报告与SonarQube等代码质量平台集成

示例Jenkins配置:

stage('Test') {
    steps {
        sh 'mvn clean verify'
    }
}
stage('Jacoco Report') {
    steps {
        jacoco execPattern: '**/target/jacoco.exec'
    }
}
1
2
3
4
5
6
7
8
9
10

# 九、最佳实践建议

  1. 统一版本管理:在父模块中统一管理JaCoCo版本
  2. 合理设置阈值:根据项目实际情况设置合理的覆盖率阈值
  3. 定期检查报告:将覆盖率检查作为代码审查的一部分
  4. 排除生成代码:避免统计自动生成代码的覆盖率
  5. 模块化配置:对于大型项目,考虑按功能模块分组统计覆盖率

通过以上配置和实践,可以在多模块项目中正确统计整体代码覆盖率,帮助团队提高代码质量和测试有效性。

# 在多模块项目中,如何排除某些子模块不参与覆盖率统计?

# 多模块项目中排除特定子模块的JaCoCo覆盖率统计方法

在大型多模块项目中,有时需要排除某些子模块不参与代码覆盖率统计,例如自动生成的代码模块、第三方库封装模块或测试工具模块等。以下是几种在不同构建工具中实现这一目标的详细方法:

# 一、Maven项目排除方法

# 1. 通过插件配置排除特定模块

在父pom.xml中配置jacoco-maven-plugin时,可以通过skip属性或excludes配置来排除特定模块:

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.7</version>
    <executions>
        <execution>
            <id>report-aggregate</id>
            <configuration>
                <!-- 排除特定模块 -->
                <excludes>
                    <exclude>**/generated/**</exclude>
                    <exclude>com/example/excluded/**</exclude>
                </excludes>
            </configuration>
        </execution>
    </executions>
</plugin>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

对于整个模块的排除,可以在特定子模块的pom.xml中添加:

<properties>
    <jacoco.skip>true</jacoco.skip>
</properties>
1
2
3

这样该模块将完全跳过JaCoCo的覆盖率统计。

# 2. 使用独立聚合模块

创建一个专门用于生成覆盖率报告的聚合模块,在该模块中只依赖需要统计覆盖率的模块:

<dependencies>
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>module-to-include-1</artifactId>
    </dependency>
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>module-to-include-2</artifactId>
    </dependency>
    <!-- 不添加需要排除的模块依赖 -->
</dependencies>
1
2
3
4
5
6
7
8
9
10
11

这种方法通过控制模块依赖关系来间接排除不需要统计的模块。

# 二、Gradle项目排除方法

# 1. 全局配置排除

在根项目的build.gradle中,可以为所有子项目配置JaCoCo并设置排除规则:

subprojects {
    plugins.withType(JavaPlugin) {
        if (!project.name.equals('module-to-exclude')) {
            apply plugin: 'jacoco'
            
            jacocoTestReport {
                afterEvaluate {
                    classDirectories.setFrom(files(classDirectories.files.collect {
                        fileTree(dir: it, exclude: [
                            '**/generated/**',
                            'com/example/excluded/**'
                        ])
                    }))
                }
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 2. 模块级排除

在需要排除的模块build.gradle中直接禁用JaCoCo:

test {
    jacoco {
        enabled = false
    }
}
1
2
3
4
5

或者更彻底地跳过测试任务:

tasks.withType(Test) {
    enabled = false
}
1
2
3

这样可以完全排除该模块的覆盖率统计。

# 三、Android项目特殊处理

对于Android多模块项目,除了上述方法外,还需要注意:

# 1. 排除特定包或类

android {
    testOptions {
        unitTests.all {
            jacoco {
                excludes = [
                    'android/**',
                    '**/R.class',
                    '**/R$*.class',
                    '**/BuildConfig.*'
                ]
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 2. 处理debug编译类型

由于Android默认使用release编译,需要确保被统计模块使用debug编译:

debug {
    testCoverageEnabled = true
}
1
2
3

同时排除模块可以保持release编译。

# 四、高级排除技巧

# 1. 基于文件模式的排除

可以使用Ant风格路径表达式排除特定模式的文件:

**/generated/**      # 排除所有generated目录下的文件
**/*Test.class       # 排除所有测试类
**/*$*.class         # 排除所有匿名内部类
1
2
3

# 2. 动态排除

通过Gradle的afterEvaluate可以在配置阶段动态决定排除内容:

jacocoTestReport {
    afterEvaluate {
        classDirectories.setFrom(files(classDirectories.files.collect {
            fileTree(dir: it, exclude: customExcludes)
        }))
    }
}
1
2
3
4
5
6
7

# 五、验证排除效果

配置完成后,可以通过以下步骤验证排除是否生效:

  1. 运行测试并生成报告:

    # Maven
    mvn clean test jacoco:report
    
    # Gradle
    gradle test jacocoTestReport
    
    1
    2
    3
    4
    5
  2. 查看生成的报告:

    • Maven项目报告位于target/site/jacoco/target/site/jacoco-aggregate/
    • Gradle项目报告位于build/reports/jacoco/
  3. 检查报告中是否确实不包含排除的模块或类。

# 六、常见问题解决

  1. 排除不生效:检查排除模式是否正确,特别是路径分隔符使用/而非\
  2. 报告为空:确保测试实际执行,且被统计模块正确配置了JaCoCo
  3. 多模块依赖问题:当A模块依赖B模块,但想排除B模块时,需要确保A模块的测试不依赖B模块的实现

通过以上方法,可以灵活地控制多模块项目中哪些模块参与覆盖率统计,从而得到更准确、更有意义的覆盖率报告。

上次更新时间: 8/3/2025, 10:09:53 AM