Java变更行单元测试覆盖率

概述

Java应用代码的单元测试覆盖率工具Jacoco已经非常成熟及完善了。对于历史的Java项目很多都是没有单元测试的,往往在新的在迭代的过程中都希望能有变更代码行的单元测试覆盖率,从而提高迭代质量。

本文介绍怎么基于jacoco和maven构建变更行单元测试覆盖率报告。对于全量单测覆盖率报告怎么使用可以参考Jacoco官方文档

获取变更行

要构建变更行测试覆盖率,那么首先我们要定位出源代码的变更文件和对应变更行号。

  1. 获取变更文件列表
git diff --name-status  ${baseCommintId} ${currentCommintId}

在这里插入图片描述

解析以上命令行结果可以获得变更文件列表
3. 获取文件变更行明细和行号

git diff -U100000 --cc -W  ${baseCommintId} ${currentCommintId} ${filePath}

在这里插入图片描述

解析返回结果,能够得到对应文件的变更行行号。

生成变更行覆盖率报告

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bCDW1Yks-1617193335708)(http://pfp.ps.netease.com/kmspvt/file/605d392c68d86415a7b4db15iZc1vgE101?sign=1gcBVlZuzh3ANY0RcdajnZur0d0=&expire=1617211329)]

JaCoCo 的注入逻辑用的是 ASM 库,都是基于JVM指令注入,比较复杂。我们用了一个比较快速简单的方式:前面生成全量覆盖率数据的流程不变,只对解析exec 文件生成报告做改造,过滤掉非变更行的行号,生成我们所需要的增量覆盖率模型。参考实现详情-Github

最佳实践

对于现在的应用,大部分都是基于Maven的多模块应用。多模块配置官方推荐

  1. 应用多模块
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sLcEBucp-1617193335709)(http://pfp.ps.netease.com/kmspvt/file/6061d0518c5674448505d3df3kjK7X8a01?sign=XNds4XHlo-ZCBDBsr3DmafK02t4=&expire=1617211329)]

多模块示例说明

  • demo-api 是应用的基础api
  • demo-service 是应用的核心业务处理模块,依赖api
  • demo-app 是应用的最终运行,依赖service
  • demo-build是独立模块,用于生成report
  1. root应用的pom.xml配置

在根pom里面设置jacoco的agent插装及单模块的测试覆盖率报告

<?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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.example</groupId>
    <artifactId>jacoco_demo</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>demo-service</module>
        <module>demo-build</module>
        <module>demo-api</module>
        <module>demo-app</module>
    </modules>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <jacoco.version>0.8.6-diff-20210324</jacoco.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco.version}</version>
                <configuration>
                    <includes>
                        <include>com/demo/**/*</include>
                    </includes>
                </configuration>
                <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>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
  1. 各子模块配置

子模块会继承root模块的配置,无需特殊配置

  1. build模块配置

build模块需要聚合各个子模块的测试报告,切生成变更行的覆盖率报告
build模块需要依赖所有的子模块
build模块需要配置git的基础commitId: mvn.git.base.commit

<?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_demo</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>demo-build</artifactId>

    <properties>
        <mvn.git.base.commit>36a2****338a</mvn.git.base.commit>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>demo-service</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>demo-app</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>demo-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco.version}</version>
                <executions>
                    &lt;-- 各模块全量覆盖率聚合报告 -->
                    <execution>
                        <id>report-aggregate</id>
                        <phase>test</phase>
                        <goals>
                            <goal>report-aggregate</goal>
                        </goals>
                    </execution>
                    
                    &lt;-- 各模块增量覆盖率聚合报告 -->
                    <execution>
                        <id>report-aggregate-diff</id>
                        <phase>test</phase>
                        <goals>
                            <goal>report-aggregate-diff</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
  1. 构建及单元测试

在根目录构建单元测试,各个子模块会生成各自模块的全量单元测试覆盖率
build模块会生成全量模块的聚合单元测试覆盖率,且会生成增量的覆盖率

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t4G7qN76-1617193335709)(http://pfp.ps.netease.com/kmspvt/file/606290eb68d864336b6a794eY9Ul1UIv01?sign=6KgVr-S6IxjGU5DyNOdZ4MyymqQ=&expire=1617211329)]

jacoco-aggregate-diff/index.html 只看行覆盖率,其他的列忽略
jacoco-aggragate/index.html 全量代码覆盖率

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PyikW6sd-1617193335710)(http://pfp.ps.netease.com/kmspvt/file/6062c48b8c5674c09a54dffdBwo0Yake01?sign=JsyKLPlS-BXnz9d_pLAFjLh9HdI=&expire=1617211329)]

后记

基于git和jaccoco的maven插件,我们能获取代码变更行的单元测试覆盖率。对于历史悠久且无单元测试的Java应用迭代可以尽量的控制增量代码单测的规范要求。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现Java单元测试的100%覆盖率,可以采取以下几个步骤: 1.设计良好的测试用例:通过充分理解代码的功能和边界条件,编写全面的测试用例。测试用例应该涵盖各种情况,包括正常情况、异常情况和边界情况。 2.使用合适的测试框架:选择适合项目需求的测试框架,如JUnit、TestNG等。测试框架提供了一些断言和辅助工具来简化测试编写和验证结果的过程。 3.模拟测试数据和环境:为了测试各种情况,可以使用Mock对象或测试替身来模拟外部依赖,以确保测试的独立性和可重复性。 4.覆盖所有代码路径:使用代码覆盖工具,例如JaCoCo,来检查测试覆盖率。通过分析覆盖率报告,可以确定哪些代码路径没有被测试到,并编写相应的测试用例。 5.遵循测试驱动开发(TDD)原则:在编写代码之前编写测试用例,确保测试用例完全覆盖了预期的功能。这有助于提前发现问题并迅速修复。 6.持续集成和自动化测试:使用持续集成工具,如Jenkins,来自动化运测试用例,并在代码提交后及时检测覆盖率。这有助于及时发现新的功能或更改引入的问题。 需要注意的是,即使采取了以上措施,也不一定能保证100%的覆盖率。有时候某些代码路径很难触发,或者由于时间和资源限制无法对所有情况进全面测试。因此,达到尽可能高的覆盖率是一个持续的过程,需要不断优化和改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值