测试左移实践 -Jacoco 代码覆盖率统计详细讲解

随着软件开发流程的不断演进,质量保障手段也在日益完善。为了更高效地发现并解决潜在问题,"测试左移"这一理念得到了广泛关注。它强调尽早介入测试,将传统后期的测试工作移到开发阶段,从而降低问题修复成本并提高交付效率。而在这一过程中,代码覆盖率作为关键的质量指标,帮助团队直观了解测试用例是否充分覆盖了代码逻辑。本文以 JaCoCo 工具为核心,详细讲解如何利用它进行代码覆盖率统计,助力企业落地测试左移实践。

Shift left vs shift right: A DevOps mystery solved

测试左移与代码覆盖率的意义

测试左移的核心目标

测试左移旨在将测试活动前置,从开发阶段开始对代码进行静态和动态检查,从而更早地发现问题。其优势包括:

代码覆盖率的作用

代码覆盖率是一种动态分析指标,用于衡量测试用例对源代码的覆盖程度。通过统计未被执行的代码路径,它能够直观反映测试用例的质量,帮助团队定位测试盲区。

JaCoCo代码覆盖率统计

JaCoCo(Java Code Coverage)是一个开源的 Java 代码覆盖率工具,主要用于在单元测试或集成测试后生成代码覆盖率报告。JaCoCo 支持生成行覆盖率、分支覆盖率等详细的代码覆盖率报告,并可通过图形化形式展示,便于开发者分析哪些代码尚未被测试覆盖。

JaCoCo 覆盖率统计原理

JaCoCo 的覆盖率统计原理是通过插桩(instrumentation)来记录代码在执行过程中的运行情况。具体来说,JaCoCo 在类加载前或类加载时对 Java 字节码插入统计指令,统计指令会记录方法调用、分支执行和代码行执行的情况,从而计算代码覆盖率。

image.png

Step1:代码插桩

JaCoCo 通过 Java Agent 的方式插桩代码。即在 JVM 启动时将 JaCoCo Agent 附加到 JVM 上,Agent 会自动加载到 JVM,并在类加载时对字节码进行修改。

插桩时,JaCoCo 会在字节码中添加计数指令,用来跟踪代码的执行情况。这些指令通常包括行覆盖和分支覆盖等信息。当被插桩的代码被执行时,这些计数器会增加,表示代码行或分支已被执行。

Step2:exec数据收集

在测试执行过程中,JaCoCo 通过插桩的代码收集覆盖率数据。当应用程序运行时,JaCoCo 会记录哪些代码行、方法、分支被执行过。这些数据通常会被存储在内存中的一个覆盖率数据文件里,通常是一个 .exec 文件。

Step3:生成覆盖率报告

执行结束后,JaCoCo 通过生成覆盖率报告来展示收集到的数据。此时可以生成多种格式的报告,例如 HTMLXMLCSV

JaCoCo代码插桩两种方式

JaCoCo 支持两种插桩方式:

在线插桩

在线插桩(On The Fly模式)是在应用运行时由 JaCoCo 自动将代码插入到需要监测的类中,以便收集代码覆盖率数据。它通过 Java Agent 技术,在 JVM 启动时将 jacocoagent.jar 附加到 JVM 中。在启动命令中添加 -javaagent:path/to/jacocoagent.jar 参数即可。

离线插桩

离线插桩是在编译之后、运行之前手动对字节码进行修改,添加用于覆盖率检测的代码。此过程通常使用 JaCoCo 提供的 Instrument 工具对字节码进行插桩。

在线插桩:适用于自动化测试、持续集成、开发测试环境中,无需提前进行字节码插桩,配置简单,维护方便。

离线插桩:适用于不支持Java Agent 的环境,字节码需要被转换成其他的虚拟机如 Android Dalvik VM,部署环境不允许设置 JVM 参数

普通Java项目插桩统计覆盖率

1、下载 JaCoCo 代理的 JAR 文件

EclEmma - JaCoCo Java Code Coverage Library

2、代码插桩

方式一:指定输出模式为file

java -javaagent:jacocoagent.jar=includes=*,output=file -jar your-application.jar

此命令启动了 Java 应用并在程序运行过程中收集覆盖率数据,覆盖率数据会在程序退出时写入 jacoco.exec 文件中。

优点:适合于一次性运行、周期性执行的应用,如单元测试、批处理程序等。数据会在程序结束时保存,无需手动触发。

缺点:需要等待应用程序完成运行后才能收集数据,无法在运行过程中实时提取覆盖率信息。

方式二:指定输出模式为tcpserver

java -javaagent:jacocoagent.jar=includes=*,output=tcpserver,port=6300,address=127.0.0.1 -jar your-application.jar

tcpserver 模式下,JaCoCo 代理会启动一个 TCP 服务器,可以通过 socket 连接实时获取覆盖率数据。适用于长时间运行的应用,如服务端应用。

优点:可以随时连接到 TCP 服务器来提取覆盖率数据,适合长期运行的服务或应用。

缺点:需要额外的客户端代码或脚本(如 Python、Java)来连接 TCP 服务器获取数据,并且需要确保端口的网络连接。

使用jacococli dump获取exec数据:

java -jar jacococli.jar dump --address 127.0.0.1 --port 6300 --destfile jacoco.exec

3、生成报告

生成覆盖率报告时,将生成的 jacoco.exec 文件作为输入,结合源码和编译类文件,生成报告。

java -jar jacococli.jar report jacoco.exec --classfiles path/to/classes --sourcefiles path/to/src --html html-report --xml report.xml --encoding=utf-8

1 操作
shakebabe 在 2025-01-14 19:30:22 更新了该帖
回帖
请输入回帖内容 ...