jacoco框架学习使用

jacoco框架学习与使用

一、jaCoco介绍

1. JaCoCo是什么?

JaCoCo(Java Code Coverage)是一个用于 Java 项目代码覆盖率工具。分析代码执行情况,评估测试用例对代码的覆盖程度,生成覆盖率报告。

JaCoCo 支持不同级别的覆盖率评估:

  • 行覆盖率(Line Coverage):每一行代码是否被执行。
  • 方法覆盖率(Method Coverage):每个方法是否被调用。
  • 类覆盖率(Class Coverage):每个类是否被加载。
  • 分支覆盖率(Branch Coverage):每个分支判断是否被执行(例如 if-else 语句)

2. 问题与优势

  1. 测试案例的设计凭经验,当研发一个新功能时,经常对测试场景估计不足,到上线后发现bug;

  2. 开发经常做一些需求之外的代码变更(代码小范围内重构或在开发过程中发现小缺陷随手改掉),导致测试任务无法测试到对应的场景,引起线上问题;

  3. 对测试效果无法量化考核,导致测试工作的质量无法进一步提升。

优势说明
代码覆盖率可视化JaCoCo 帮助开发者直观地查看代码的测试覆盖情况
提高代码质量通过评估测试覆盖率,帮助识别潜在的代码缺陷和测试盲点
代码审查与评估提供覆盖率报告,支持团队评估项目质量并指导开发工作
确保测试用例全面性确保测试用例覆盖大部分代码路径,而不仅仅是执行某些代码
开源轻量性能良好,运行时开销很小,尤其是对于大型项目;
易于集成JaCoCo 提供了 CLI 工具Maven 插件ant 插件,以及与 Jenkins 等 CI 工具的集成支持。

3. jacoco原理

JaCoCo支持几种不同的方法来收集覆盖信息,对于每种方法,由不同技术实现的,下图橙色路径部分是JaCoCo 推荐使用的方式,即通过On-The-Fly方式收集覆盖率信息:

img

通过上图我们知道,JaCoCo 是通过对Java字节码(Byte Code)插入探针的方式来收集覆盖率信息的,探针是可以插入现有指令之间的附加指令。它们不会改变方法的行为,但会记录它们已被执行的事实。

下面以一段简单的 程序为例进行说明:

img

这段代码经过Java编译以后转化为以下字节码:

img

因为Java 字节码指令的线性序列,控制流是通过条件或无条件指令实现跳转的,跳转目标在技术上是相对于目标指令的偏移量。这个跟大学学习的汇编指令的跳转方式类似,为了更好的可读性,使用符号标签 (L1,L2 ) 代替实际的指令地址。

img

上图中橙色的部分为插入的探针,理论上我们可以在控制流图的每个边缘插入一个探针,由于探针实现本身需要一些字节码指令,这将会使类文件的大小增加数倍;幸运的是,这不是必需的,实际上我们只需要根据方法的控制流为每个方法插入几个探针。例如,没有任何分支的方法只需要一个探针。

如果已经执行了探测,我们就知道相应的边已经被访问过。从这条边我们可以得出结论到其他前面的节点和边:

  • 如果一条边被访问过,我们就知道这条边的源节点已经被执行了;
  • 如果一个节点已经被执行并且该节点是只有一条边的目标,我们知道这条边已经被访问过。

如果我们在正确的位置有探针,递归地应用这些规则可以确定方法的所有指令的执行状态,探针只是需要在控制流边缘插入的一小段附加指令。

4. 流程:

JaCoCo 的工作原理基于 字节码增强插桩技术,主要步骤如下:

  1. 字节码插桩:
    • JaCoCo 在程序编译后对 Java 字节码 进行修改(插桩)。这意味着 JaCoCo 会修改 .class 文件中的字节码,在方法执行前后插入额外的代码,用于记录代码是否被执行过。
    • 当你运行测试时,JaCoCo 会跟踪代码的执行,并记录 哪些方法、行或分支 被执行。
  2. 运行时数据收集:
    • JaCoCo 插桩的代码在运行时会跟踪哪些部分的代码被执行。当你运行 Java 程序时,JaCoCo 会生成一个 覆盖率数据文件(例如 .exec 文件),它记录了程序执行过程中哪些行代码被触发。
  3. 覆盖率报告生成:
    • 运行完测试用例后,JaCoCo 会根据收集到的数据生成 代码覆盖率报告。这个报告可以是 HTML、XML 或 CSV 格式,展示每个类、方法、行的覆盖情况。
    • 报告能够清晰地显示哪些代码行被测试覆盖,哪些没有被执行。通过这些信息,开发者可以做出改进和优化,确保测试的充分性。

二、单元测试集成jacoco

​ 开发人员进行单元测试的时候,可以通过集成jacoco插件的形式,生成单元测试的代码覆盖率,针对未覆盖的代码编写更多的测试用例,以确保代码的全面覆盖,从而提高代码质量和可靠性。

本示例是基于springBoot+maven的组合。

1. 引入jaCoco的maven插件

<build>
    <plugins>
        <plugin>
            <!-- JaCoCo的 Maven 插件,用于生成代码覆盖率报告 -->
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.6</version>
            <executions>
                 <!-- 第一个任务prepare-agent编译阶段执行,它负责准备 JaCoCo 代理,以便在测试运行时收集覆盖率数据。-->
                <execution>
                    <goals>
                        <goal>prepare-agent</goal>
                    </goals>
                </execution>
               <!-- 第二个任务在 test 阶段执行,目标是 report。这个执行阶段生成代码覆盖率报告-->
                <execution>
                    <id>jacoco-report</id>
                    <phase>test</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                </execution>
                <!-- 非必需:配置的规则检查覆盖率是否达标。如果覆盖率不满足配置的要求,构建将失败。-->
                <execution>
                    <id>jacoco-check</id>
                    <goals>
                        <goal>check</goal>
                    </goals>
                    <configuration>
                        <rules>
                            <rule>
                                <element>PACKAGE</element>
                                <limits>
                                    <limit>
                                        <counter>LINE</counter>
                                        <value>COVEREDRATIO</value>
                                        <minimum>0.0</minimum>
                                    </limit>
                                </limits>
                            </rule>
                        </rules>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <!-- 这个插件用于执行 Maven 构建中的测试 -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.0.0-M5</version>
            <configuration>
                <!--该配置设定了单元测试执行结束后,Maven等待进程退出的最长时间(单位:秒)-->
                <forkedProcessExitTimeoutInSeconds>60</forkedProcessExitTimeoutInSeconds>
                <!-- 设置fork的进程数,1 表示只启动一个进程执行测试。如果你需要并行执行测试,可以增加该值  -->
                <forkCount>1</forkCount>
            </configuration>
        </plugin>
    </plugins>
</build>

上述配置引入两个maven插件jacoco-maven-plugin(jacoco插件相关)、maven-surefire-plugin(执行maven构建中的测试)

2. 编写单元测试类

//服务类
@Slf4j
@Service
public class CustomerApplication {
    @Resource
    private CrmChargeUserMapper crmChargeUserMapper;
    @Resource
    private CrmBusEncryptMapper crmBusEncryptMapper;
    public void getAreaInfo() {
        String areaNames = "北京";
        TableFieldEnum customer = TableFieldEnum.CUST_CUST_INFO;
        DynamicDataSource.setDataSourceType(customer.getDataBaseName());
        //有if 分支 所以这个接口会走if里面的,外边的不会走,则编写单元测试执行后代码覆盖率为50%
        if(StringUtils.isBlank(areaNames)){
            List<PhoneEncryptPO> phoneEncryptPOS = crmBusEncryptMapper.selectDataListByIds(customer.getDataBaseName(), customer.getTableName()
                    , customer.getIdField(), customer.getPhoneField(), Lists.newArrayList(2035279L));
            log.info("查询客户信息:{}", phoneEncryptPOS);
            return;
        }
        List<AreaInfo> areaInfos = crmChargeUserMapper.selectAreaList(Lists.newArrayList(areaNames));
        log.info("查询区域信息:{}", areaInfos);
    }
}

//单元测试
@Slf4j
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = ToolApplication.class)
@WebAppConfiguration
public class CrmBusEncryptServiceTest {
    @Resource
    private CustomerApplication customerApplication;
    //单元测试
    @Test
    public void getAreaInfo() {
        customerApplication.getAreaInfo();
    }
}

3. 执行测试流程

通过idea的maven管理插件、或者mvn test命令执行完毕,会生成对应的xxx.exec文件(可以通过jacococli 将exec文件转换成html查看覆盖率)

在这里插入图片描述

其中会生成jacoco.exec,html的覆盖率报告在target/site目录下。

覆盖率报告如下:和上面单元测试类预估的覆盖率一致为50%
在这里插入图片描述

三、项目整合jacoco

上面我们说了单元测试如何整合jacoco,但是不是每个开发都会写单元测试(不会为整个项目都写测试用例)。测试人员需要针对项目http接口进行覆盖率的分析。所以此章节项目整合jacoco框架。

主要流程:

  1. 下载安装jacoco
  2. java项目启用配置的javagent,并请求api接口
  3. 下载覆盖率报告并生成覆盖率报告

1. 安装jacoco

jacoco下载地址

里面详细罗列了所有按需下载的jacoco 版本,下载并解压到指定目录,此处和单元测试使用jacoco版本一致使用0.8.6

#下载并解压(第二种下载方式)
#下载jacoco 
wget http://search.maven.org/remotecontent?filepath=org/jacoco/jacoco/0.8.6/jacoco-0.8.6.zip 
#解压
unzip jacoco-0.8.6.zip
软件包功能
jar包功能关键说明
jacocoagent.jar作为Java代理通过JVM的javaagent参数注入到运行中,实时对字节码进行插桩(On-the-fly Instrumentation),跟踪代码执行路径。接口测试或需要长期监控覆盖率的场景。
jacococli.jar提供命令行接口(CLI),支持覆盖率数据的导出、合并、报告生成及离线插桩操作。dump:导出实时覆盖率数据到.exec文件
report:解析文件,结合源码和编译文件生成HTML/XML/CSV格式的覆盖率报告
merge:合并多个.exec文件,支持多轮测试数据的整合分析
jacocoant.jar将JaCoCo与Apache Ant构建工具深度集成,通过自定义Ant任务自动化覆盖率分析流程。类似于maven、gradle构建工具
工作流程
  1. 启动应用:通过-javaagent:jacocoagent.jar参数附加代理,启动TCP Server。
  2. 执行测试:运行单元测试或手动测试,覆盖目标代码。
  3. 导出数据:使用jacococli.jar dump命令从TCP Server导出.exec文件。
  4. 生成报告:通过jacococli.jar report或Ant任务生成可视化报告。
  5. 分析优化:根据报告识别未覆盖代码,迭代改进测试用例。

2、配置jacoco

在项目启动脚本(strat.sh)或者本地idea的vm options 添加代理配置

#-javaagent:[jacoco软件安装路径/]jacocoagent.jar=includes=包名,output=tcpserver,port=端口,address=ip 
javaagent:/usr/local/jacoco/lib/jacocoagent.jar=includes=*
,output=tcpserver,port=6200,address=127.0.0.1,append=true 
参数名称作用示例值注意事项
includes指定需要收集覆盖率的类(支持通配符匹配)includes=com.xieqx.*默认值为 *,表示包含所有类
excludes排除特定类或包(避免收集无关代码)excludes=com.xieqx.test.*-
output设置覆盖率数据输出方式output=tcpserver可选值:file(写入文件)、tcpserver(启动TCP服务器)、tcpclientnone
append控制数据追加行为append=truetrue:追加数据到现有文件;false:覆盖文件(默认)
address指定TCP服务器绑定的网络接口address=** 表示监听所有接口;生产环境建议限制为特定IP
port设置TCP服务器监听的端口号port=6200确保端口未被占用,且与客户端配置一致
dumponexitJVM退出时自动导出覆盖率数据dumponexit=true默认值为 false,适用于短期运行的测试任务
outputfile指定输出文件路径(仅在 output=file 模式有效)outputfile=./coverage.exec-
classdumpdir转储代理处理的类文件到指定目录(用于调试动态生成的类)classdumpdir=/path/to/classes-
jmx启用JMX接口(允许远程监控和管理覆盖率数据)jmx=true-
sessionid为覆盖率数据分配唯一会话ID(便于多实例区分数据)sessionid=12345-
exclclassloader排除特定类加载器加载的类(避免框架内部类干扰统计)

3、生成覆盖率报告

项目启动后,请求项目相关api接口。即会产生覆盖率报告。后面我们需要将对应的覆盖率dump(下载)下来(xxx.exec文件),并report生成html(xml/csv)覆盖率报告。

dump覆盖率报告
# 注意因为上面启动时tcpserver 且设置了允许远程ip端口,所以处理需要和上面ip端口保持一致
java -jar /usr/local/jacoco/lib/jacococli.jar dump --address 127.0.0.1 --port 6200 --destfile /Users/xie qx/Documents/jacoco-demo.exec
参数描述
address指定JaCoCo代理运行的TCP服务器的地址。例如,--address 127.0.0.1
port指定JaCoCo代理运行的TCP服务器的端口号。例如,--port 6300
destfile指定生成的覆盖率数据文件的路径和名称。例如,--destfile ./jacoco.exec
reset可选参数,表示在dump操作后是否重置覆盖率数据。如果设置为true,则重置数据;如果设置为false或不设置,则不重置数据。
retry可选参数,表示在连接失败时重试的次数。例如,--retry 10表示重试10次。
quiet可选参数,表示是否以静默模式运行,不输出详细信息。

上述dump操作会在我们destfile对应目录中生成jacoco-demo.exec。

report覆盖率报告

dump下来的覆盖率只是exec没法查看具体的信息。所以需要使用report导出为html(xml/csv)等进行查看

java -jar ${jacoco的安装路径}/lib/jacococli.jar 
     report ${生成的覆盖率文件路径}/jacoco-demo.exec
     --classfiles /{项目路径}/target/classes/com 
     --sourcefiles  /{项目路径}/src/main/java 
     --html /Users/yiche/Documents/report 
参数描述
<execfiles>指定一个或多个包含覆盖率数据的执行文件(.exec 文件),多个文件之间用逗号分隔。
--classfiles <path>指定包含被测试类文件(.class 文件)的目录或文件路径。JaCoCo 将从这个路径加载对应的类文件以生成覆盖率报告。
--sourcefiles <path>指定源代码文件的目录或文件路径,以便在生成的报告中附加源代码信息。
--html <dir>指定生成 HTML 格式报告的输出目录。
--xml <file>指定生成 XML 格式报告的输出文件路径。
--csv <file>指定生成 CSV 格式报告的输出文件路径。
--title <title>设置生成报告的标题。
--name <name>设置生成报告的名称,用于标识不同的报告。
--filters <filter>用于指定过滤器,以排除某些特定的类或包。过滤器使用 Java 的包命名规则,可以使用星号(*)作为通配符。
--encoding <charset>指定生成报告时使用的字符编码,例如 UTF-8
--tabwith <n>设置生成报告时使用的制表位宽度。
--quiet可选参数,表示以静默模式运行,不输出详细信息。
--help显示 report 命令的帮助信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值