测试左移

代码分析、单元测试、覆盖率统计

大纲

1. 代码审计 SonarQube 平台搭建 2. SonarQube Scanner 使用 3. SonarQube Maven 项目分析 4. SonarQube Gradle 项目分析 5. 代码复杂度分析 6. 代码扫描规则定制 7. SonarQube API 使用 8. 代码变更检测与新增代码覆盖率实战 9. JaCoCo 代码覆盖率 10. JaCoCo 代码插桩原理介绍
  1. 单测代码覆盖率统计实战

  2. Maven 项目代码覆盖率统计

  3. jacococli 工具

  4. 集成代码覆盖率统计实战

  5. Maven 项目代码分析

  6. 代码 Bug 分析

  7. 代码复杂度分析

  8. 代码质量门禁

  9. SonarQube 与持续集成结合

测试左移介绍

为什么要做测试左移

Applied Software Measurement, Capers Jones, 1996

微软的左移实践

微软

测试左移主要实践

  • 需求分析与评审
  • 代码评审
  • 代码审计、代码静态分析
  • 单元测试
  • 覆盖率统计


  • 自动化测试左移
  • 应用监控
  • 测试用例生成

sonarqube 技术架构图

sonarqube 项目分析案例

典型 bug 案例

代码分析技术体系

ceshiren.com

霍格沃兹测试开发

代码分析工具

  • IDE 辅助功能
    • xcode、android studio
    • 阿里巴巴 java 开发手册 ide 插件支持
  • 独立的静态分析工具
    • spotbugs、findbugs、androidlint、scan-build、Checkstyle、FindSecBugs
    • pmd 阿里巴巴 java 开发手册 pmd 插件
  • 综合性的代码分析平台
    • sonarqube 功能强大,数据分析全面

代码分析技术架构

  • 代码静态检查
    • 代码分析:通过分析语法树和源代码,检查代码规范
      • lint 系列 style 系列 pmd
      • antlr
    • 编译器分析:借助于编译器获得代码关系
  • 字节码静态分析
    • 分析 jar、war、dex 等格式的文件,代表工具:findbugs asm

语法树分析技术

while b ≠ 0
if a > b
a := a − b
else
b := b − a
return a

字节码分析技术 Java 与 Kotlin 源代码

public class ControlFlow {
    public static void main(String[] args) {
        int a = 1;
        while (a < 10) {
            a++;
            if (a < 5) {
                System.out.println("a<5");
            } else {
                System.out.println("a>=5");
            }
        }
    }
}
object ControlFlow {
    @JvmStatic
    fun main(args: Array<String>) {
        var a = 1
        while (a < 10) {
            a++
            if (a < 5) {
                println("a<5")
            } else {
                println("a>=5")
            }
        }
    }
}

字节码分析技术-java 字节码

Compiled from "ControlFlow.java"
public class com.hogwarts.instrument.ControlFlow {
  public com.hogwarts.instrument.ControlFlow();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1
       1: istore_1
       2: iload_1
       3: bipush        10
       5: if_icmpge     38
       8: iinc          1, 1
      11: iload_1
      12: iconst_5
      13: if_icmpge     27
      16: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      19: ldc           #3                  // String a<5
      21: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      24: goto          2
      27: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      30: ldc           #5                  // String a>=5
      32: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      35: goto          2
      38: return
}

SonarQube

  • The leading product for Code Quality and Security
  • Static code analysis for 17 languages
  • Detect Bugs & Vulnerabilities
  • Review Security Hotspots
  • Track Code Smells & fix your Technical Debt
  • Code Quality Metrics & History
  • CI/CD integration
  • Extensible, with 50+ community plugins

代码分析主要指标

代码分析细节指标

度量指标总结

  • 可靠性 bugs
  • 可维护性 code smells
  • 安全性 Vulnerabilities Security Hotspots
  • 覆盖率 Coverage Unit Tests
  • 代码重复 Duplications
  • 代码规模 Lines of Code Comments rate
  • 复杂度 Cyclomatic Complexity Cognitive Complexity

独立分析平台使用案例

持续集成使用案例

sonarqube 经典案例分析

目前大部分公司都采用了 sonarqube,它的概念和技术指标已经成为行业事实上的标准

SonarQube 平台搭建

sonarqube 技术架构

临时部署方案

#通用部署
docker run -d \
  --name sonarqube_temp \
  -p 9000:9000 -p 9092:9092 \
  sonarqube

#mac部署
docker run -d \
  --name sonarqube_temp \
  -p 9000:9000 -p 9092:9092 \
  --platform linux/x86_64 \
  -e SONAR_SEARCH_JAVAADDITIONALOPTS="-Dbootstrap.system_call_filter=false" \
  sonarqube

正式环境部署

#创建容器网络
docker network create sonarqube

#创建数据库容器实例
docker run -d \
  --name sonarqube_postgres \
  --network sonarqube \
  -e POSTGRES_USER=sonarqube \
  -e POSTGRES_PASSWORD=sonarqube \
  -e PGDATA=/var/lib/postgresql/data/pgdata \
  -v $PWD/postgresql_data:/var/lib/postgresql/data \
  postgres

#创建sonarqube容器实例,可以通过-Xms4g -Xmx4g增加下ES的堆内存大小
#mac环境需要加 -e SONAR_SEARCH_JAVAADDITIONALOPTS="-Dbootstrap.system_call_filter=false"
docker run -d  \
  --name sonarqube_hogwarts \
  -p 9000:9000 -p 9092:9092 \
  --network sonarqube \
  -e SONARQUBE_JDBC_USERNAME=sonarqube \
  -e SONARQUBE_JDBC_PASSWORD=sonarqube \
  -e SONARQUBE_JDBC_URL="jdbc:postgresql://sonarqube_postgres/sonarqube" \
  -e SONAR_SEARCH_JAVAADDITIONALOPTS="-Xms2g -Xmx2g" \
  -e SONARQUBE_WEB_JVM_OPTS="-Xms1g -Xmx1g" \
  -v $PWD/sonarqube_data:/opt/sonarqube/data \
  -v $PWD/sonarqube_extensions:/opt/sonarqube/extensions \
  -v $PWD/sonarqube_logs:/opt/sonarqube/logs \
  sonarqube

学社公共演练环境

仅用于学习与参考

https://sonarqube.stuq.ceshiren.com/

vm.max_map_count too lowt 解决问题

max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

#临时方案
sysctl -w vm.max_map_count=262144
#永久方案 添加一行到/etc/sysctl.conf
vm.max_map_count=262144

个别平台存在的 CONFIG_SECCOMP_FILTER 问题

java.lang.UnsupportedOperationException: seccomp unavailable: CONFIG_SECCOMP not compiled into kernel, CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER are needed

CONFIG_SECCOMP_FILTER 问题解决方法

#创建sonarqube容器实例
docker run -d  \
  --name sonarqube_hogwarts \
  --platform linux/x86_64 \
  -p 9000:9000 -p 9092:9092 \
  --network sonarqube \
  --user $(id -u):$(id -g) \
  -e SONARQUBE_JDBC_USERNAME=sonarqube \
  -e SONARQUBE_JDBC_PASSWORD=sonarqube \
  -e SONARQUBE_JDBC_URL="jdbc:postgresql://sonarqube_postgres/sonarqube" \
  -e SONAR_SEARCH_JAVAADDITIONALOPTS="-Dbootstrap.system_call_filter=false -Xms1g -Xmx1g" \
  -e SONARQUBE_WEB_JVM_OPTS="-Xms1g -Xmx1g" \
  --ulimit nofile=524288:524288 \
  -v $PWD/sonarqube_data:/opt/sonarqube/data \
  -v $PWD/sonarqube_extensions:/opt/sonarqube/extensions \
  -v $PWD/sonarqube_logs:/opt/sonarqube/logs \
  sonarqube

调整 JVM Heap Size 加速

-e SONAR_SEARCH_JAVAADDITIONALOPTS="-Xms1g -Xmx4g"
-e SONAR_SEARCH_JAVAADDITIONALOPTS="-Dbootstrap.system_call_filter=false -Xms1g -Xmx4g"

环境配置

  • 默认账号 admin:admin
  • 生成 token
  • 划分组与用户

环境变量设置

- 为了方便命令复用,后面命令中可变内容使用环境变量来表示 $SQ_HOST
SQ_HOST=http://127.0.0.1:9000
SQ_TOKEN=你自己sonarqube环境的TOKEN

SQ_HOST=https://sonarqube.stuq.ceshiren.com
SQ_TOKEN=a22c79622b232ffb002053a06b5cb3140da87b41

插件安装与配置

sonarqube 基本环境配置完成,接下来我们就可以去用 scanner 分析代码了

sonarqube scanner 使用

scanner 工具体系

  • Gradle - SonarScanner for Gradle
  • .NET - SonarScanner for .NET
  • Maven - use the SonarScanner for Maven
  • Jenkins - SonarScanner for Jenkins
  • Azure DevOps - SonarQube Extension for Azure DevOps
  • Ant - SonarScanner for Ant
  • anything else (CLI) - SonarScanner

代码分析配置

  • 配置文件形式
    • sonar-project.properties
    • 构建工具配置 maven gradle
  • 参数传递形式 sonar-scanner -Dsonar.projectKey=myproject -Dsonar.sources=src1

常用配置

配置 描述 默认值
sonar.host.url the server URL http://localhost:9000
sonar.projectKey 项目唯一标记 For Maven projects, this defaults to <groupId>:<artifactId>
sonar.projectName 项目显示名字 <name> for Maven projects
sonar.login 权限认证 token
sonar.ws.timeout 最大超时时间 60
sonar.sources 逗号分割的源代码目录 默认当前目录,或者从构建工具中读取
sonar.newCode.referenceBranch 是否是新代码的判断基准分支 按照当前变更

官方示例演练

git clone https://github.com/SonarSource/sonar-scanning-examples.git
cd sonar-scanning-examples

sonar-scanner 工具使用

cd sonarqube-scanner
sonar-scanner -Dsonar.host.url=$SQ_HOST -Dsonar.login=$SQ_TOKEN

#docker方式
docker run --rm -e SONAR_HOST_URL=$SQ_HOST -e SONAR_LOGIN=$SQ_TOKEN -v /tmp/demo:/usr/src sonarsource/sonar-scanner-cli

sonarqube maven 项目分析

maven 全局配置

<settings>
    <pluginGroups>
        <pluginGroup>org.sonarsource.scanner.maven</pluginGroup>
    </pluginGroups>
    <profiles>
        <profile>
            <id>sonar</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <!-- Optional URL to server. Default value is http://localhost:9000 -->
                <sonar.host.url>
                  http://myserver:9000
                </sonar.host.url>
            </properties>
        </profile>
     </profiles>
</settings>

使用特定版本 scanner maven 插件

mvn sonar:sonar
mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.7.0.1746:sonar
mvn org.sonarsource.scanner.maven:sonar-maven-plugin:LATEST:sonar

代码分析基本命令

#编译后直接分析
mvn clean compile sonar:sonar
#执行单元测试后分析,用于收集单元测试与单测覆盖率
mvn clean test sonar:sonar
#执行集成测试后分析,用于收集集成测试与集成测试覆盖率
mvn clean verify sonar:sonar

maven 单模块项目代码分析

cd maven-basic
mvn clean verify \
  org.sonarsource.scanner.maven:sonar-maven-plugin:LATEST:sonar \
  -Dsonar.host.url=$SQ_HOST   \
  -Dsonar.login=$SQ_TOKEN

maven 多模块项目代码分析

cd maven-multimodule
mvn clean verify \
  org.sonarsource.scanner.maven:sonar-maven-plugin:LATEST:sonar \
  -Dsonar.host.url=$SQ_HOST   \
  -Dsonar.login=$SQ_TOKEN

sonarqube 多语言代码分析

cd maven-multilingual
mvn clean verify \
  org.sonarsource.scanner.maven:sonar-maven-plugin:LATEST:sonar \
  -Dsonar.host.url=$SQ_HOST   \
  -Dsonar.login=$SQ_TOKEN

spring boot 项目代码分析

mvn clean compile \
  org.sonarsource.scanner.maven:sonar-maven-plugin:LATEST:sonar \
  -Dsonar.host.url=$SQ_HOST   \
  -Dsonar.login=$SQ_TOKEN

电商项目代码分析

mvn clean verify \
  org.sonarsource.scanner.maven:sonar-maven-plugin:LATEST:sonar \
  -Dsonar.host.url=$SQ_HOST   \
  -Dsonar.login=$SQ_TOKEN

maven 的基本分析命令已经熟悉了,快去在自己的项目中练习下吧。后面的章节我们会进一步教大家收集测试用例与覆盖率数据

sonarqube gradle 项目代码分析

sonarqube scanner gradle 插件与配置

// build.gradle
plugins {
  id "org.sonarqube" version "3.3"
}

sonarqube {
    properties {
        property "sonar.host.url", "https://sonarqube.hogwarts.ceshiren.com"
        property "sonar.login", "a22c79622b232ffb002053a06b5cb3140da87b41"
        property "sonar.sourceEncoding", "UTF-8"
    }
}
# gradle.properties
systemProp.sonar.host.url=http://localhost:9000

gradle 代码分析命令

#多任务执行
./gradlew clean assemble sonarqube \
  -Dsonar.host.url=$SQ_HOST \
  -Dsonar.login=$SQ_TOKEN

#也可单独执行
gradle sonarqube \
  -Dsonar.host.url=$SQ_HOST \
  -Dsonar.login=$SQ_TOKEN

简单 gradle 项目代码分析

cd gradle-basic
./gradlew clean assemble sonarqube \
  -Dsonar.host.url=$SQ_HOST \
  -Dsonar.login=$SQ_TOKEN

gradle 项目代码分析结合覆盖率

cd gradle-multimodule-coverage
./gradlew clean build \
  codeCoverageReport \
  sonarqube -Dsonar.host.url=$SQ_HOST -Dsonar.login=$SQ_TOKEN

Appium UiAutomator2 Server

Appium UiAutomator/UiObject2-based server for Android UI automation. This module is used by appium-uiautomator2-driver component

./gradlew clean \
  assembleServerDebug \
  assembleServerDebugAndroidTest \
  sonarqube \
  -Dsonar.host.url=$SQ_HOST \
  -Dsonar.login=$SQ_TOKEN

恭喜你获得了 gradle 项目的代码分析能力,快在自己公司的项目中用起来吧。一般移动端项目使用 gradle 是比较多的。

常见代码 Bug 解读

常见代码 bug

  • 空指针
  • 数据类型
  • 随机数
  • 安全漏洞

代码扫描规则定制

sonarqube api 使用

代码审计系统 SonarQube 实战

测试用例与代码覆盖率数据分析实战

代码变更检测与新增代码覆盖率实战

sonarqube 代码分析实战流程

  • 环境搭建:利用 docker 搭建产品化环境(参考前面章节)
  • 环境配置:生成并获得 token
  • 持续集成:选择被测项目,并构建持续集成环境 gitlab jenins
  • 技术选型:根据被测项目类型选择合适的 scanner 用法
  • 执行分析:配置并执行分析
  • 数据分析:通过 sonarqube 平台分析数据
  • 数据回传:把数据同步回项目

maven 项目分析实战

start.spring.io

sonarqube scanner maven 插件

mvn \
  clean \
  compile \
  test \
  org.sonarsource.scanner.maven:sonar-maven-plugin:LATEST:sonar  \
  -Dsonar.host.url=$SQ_HOST   \
  -Dsonar.login=$SQ_TOKEN

相关链接

  • https://docs.sonarqube.org/latest/analysis/scan/sonarscanner-for-maven/
  • https://docs.sonarqube.org/latest/analysis/scan/sonarscanner-for-gradle/
  • https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/

代码覆盖率统计 Jacoco

霍格沃兹测试开发

ceshiren.com

jacoco 介绍

JaCoCo is a free code coverage library for Java, which has been created by the EclEmma team based on the lessons learned from using and integration existing libraries for many years.

JaCoCo 是一个免费的 Java 代码覆盖库,它是由 EclEmma 团队根据多年来使用和集成现有库的经验教训创建的。

常见的 Java 代码覆盖率工具

  • jacoco
  • cobertura
  • emma ( base on jacoco )

为什么选择 jacoco

There are several open source coverage technologies for Java available. While implementing the Eclipse plug-in EclEmma the observation was that none of them are really designed for integration . Most of them are specifically fit to a particular tool (Ant tasks, command line, IDE plug-in) and do not offer a documented API that allows embedding in different contexts. Two of the best and widely used available open source tools are EMMA and Cobertura. Both tools are not actively maintained by the original authors any more and do not support the current Java versions. Due to the lack of regression tests maintenance and feature additions is difficult.

为什么选择 jacoco 中文

有几种可用的 Java 开源覆盖技术。在实现 Eclipse 插件 EclEmma 时,观察到它们都不是真正为集成而设计的。它们中的大多数专门适用于特定工具(Ant 任务、命令行、IDE 插件),并且不提供允许嵌入不同上下文的文档化 API。两个最好的和广泛使用的开源工具是 EMMA 和 Cobertura。这两个工具都不再由原作者积极维护,也不支持当前的 Java 版本。由于缺乏回归测试,维护和功能添加很困难。

jacoco 特点

  • 覆盖率分析指标丰富 Coverage analysis of instructions (C0), branches (C1), lines, methods, types and cyclomatic complexity.
  • 可以不依赖源代码 Based on Java byte code
  • 集成方式灵活 Simple integration
  • 开发框架无关 Framework agnostic
  • 兼容所有的 java 版本 Compatible with all released Java class file versions.
  • java kotlin scala 等多 jvm 语言支持 Support for different JVM languages.
  • 多种报告格式 Several report formats (HTML, XML, CSV).
  • 允许远程控制 Remote protocol and JMX
  • 有独立的工具与 ant maven 的集成支持

Jacoco 支持的覆盖率指标

  • 指令覆盖率 Instructions
  • 分支覆盖率 Branches
  • 圈复杂度覆盖率 Cyclomatic Complexity V(G)=e-n+2p
  • 代码行覆盖率 Lines
  • 方法覆盖率 Methods
  • 类覆盖率 Classes

那些暂未支持的覆盖率指标

  • 条件覆盖率(Condition coverage)每一个逻辑表达式中的每一个条件(无法再分解的逻辑表达式)是否都有运行到成立及不成立的情形
  • 条件/判断覆盖率(Condition/decision coverage)需同时满足判断覆盖率和条件覆盖率
  • 修改条件/判断覆盖 modified condition/decision coverage,简称 MC/DC 影响判断结果的条件中,每个变量都出现至少二次,其中至少一次其值为真,至少一次其值为假
  • 循环覆盖率(Loop coverage)所有循环是否都有运行过零次、一次及一次以上的测试
  • 参数值覆盖率(Parameter Value Coverage)对于一个方法的所有参数,是否有运行过其中最常见的数值?

Jacoco 技术原理

字节码插桩原理

public static void example() {
    a();
    if (cond()) {
        b();
    } else {
        c();
    }
    d();
}
public static example()V
      INVOKESTATIC a()V
      INVOKESTATIC cond()Z
      IFEQ L1
      INVOKESTATIC b()V
      GOTO L2
  L1: INVOKESTATIC c()V
  L2: INVOKESTATIC d()V
      RETURN

插桩方式

offline 插桩模式应用场景

  • 不支持 java agent; Runtime environments that do not support Java agents.
  • 不支持配置 jvm 参数;Deployments where it is not possible to configure JVM options.
  • 字节码不兼容的平台;Bytecode needs to be converted for another VM like the Android Dalvik VM.
  • 与其他 agent 冲突;Conflicts with other agents that do dynamic classfile transformation.

Jacoco 下载与配置

  • JACOCO_HOME 设置环境变量,方便后续引用,你可以修改为你的 jacoco 本地地址
  • export JACOCO_HOME=/Users/seveniruby/ke/shift_left/jacoco-0.8.9

Jacoco 主要文件

文件 用途
lib/jacocoagent.jar on the fly 运行时插桩用到的 java agent
lib/jacococli.jar jacoco 的命令行工具

Jacoco 使用流程

  • instruments
  • testcase 执行测试
  • dump 导出覆盖率数据
  • merge 覆盖率数据合并
  • report 生成报告

集成测试代码覆盖率统计

霍格沃兹测试开发

ceshiren.com

演练环境 Spring Start

#请使用Java 17运行
git clone https://github.com/spring-io/start.spring.io.git
cd start.spring.io
#设置一个变量,保存起来方便后续引用
export START_SPRING_IO_HOME=$PWD
./mvnw clean package -Dmaven.gitcommitid.skip=true -Dmaven.test.skip=true
#启动被测应用
java -jar $START_SPRING_IO_HOME/start-site/target/start-site-exec.jar

配置环境变量

#vim ~/.bash_profile
#修改为你的本地对应地址,每个人可能不同
export JACOCO_HOME=$HOME/ke/shift_left/jacoco-0.8.9
export START_SPRING_IO_HOME=$HOME/ke/shift_left/start.spring.io

运行时插桩

```bash {: style="white-space: pre-wrap"} java -javaagent:$JACOCO_HOME/lib/jacocoagent.jar=output=tcpserver -jar $START_SPRING_IO_HOME/start-site/target/start-site-exec.jar


---

### on-the-fly 运行时插桩的多种模式

```bash
#本地文件模式
java -javaagent:$JACOCO_HOME/lib/jacocoagent.jar \
  -jar $START_SPRING_IO_HOME/start-site/target/start-site-exec.jar

#tcpserver模式 默认6300端口
java -javaagent:$JACOCO_HOME/lib/jacocoagent.jar=output=tcpserver \
  -jar $START_SPRING_IO_HOME/start-site/target/start-site-exec.jar

dump 导出覆盖率数据

#删除之前的exec文件,不然会自动合并以前的结果
rm jacoco_tcpserver.exec
java -jar $JACOCO_HOME/lib/jacococli.jar \
  dump \
  --address 127.0.0.1 --port 6300 \
  --reset \
  --destfile jacoco_tcpserver.exec

report 生成覆盖率报告

#生成无源代码的报告
java -jar $JACOCO_HOME/lib/jacococli.jar \
  report jacoco_tcpserver.exec \
  --html jacoco_html \
  --classfiles $START_SPRING_IO_HOME/start-site/target/classes/

java -jar $JACOCO_HOME/lib/jacococli.jar \
  report jacoco_tcpserver.exec \
  --html jacoco_html \
  --classfiles $START_SPRING_IO_HOME/start-site/target/start-site-exec.jar \
  --classfiles $START_SPRING_IO_HOME/start-site/target/start-site.jar

使用 jar 可能会存在 class 冲突的问题

Caused by: java.lang.IllegalStateException: Can't add different class with same name: org/apache/logging/log4j/util/StackLocator

  • 解压所有 jar 到某个特定的目录
  • 以 class 目录作为 classfiles 的参数值

生成有源代码关联的报告

java -jar $JACOCO_HOME/lib/jacococli.jar \
  report jacoco_tcpserver.exec \
  --html jacoco_html \
  --classfiles $START_SPRING_IO_HOME/start-site/target/classes/ \
  --sourcefiles $START_SPRING_IO_HOME/start-site/src/main/java/

带有源代码的报告

集成测试覆盖率统计流程

  • instruments 插桩并启动
  • test 执行测试,手工测试、自动化测试
  • dump 导出覆盖率数据
  • merge 覆盖率数据合并
  • report 生成报告

掌握了如何获取集成测试覆盖率后,我们就可以根据覆盖率数据与未覆盖代码,来针对性的改进我们的手工测试与自动化测试了。

单元测试代码覆盖率统计

单元测试的代码覆盖率统计方法

  • 通过构建工具插件集成 ant maven gradle
  • 执行测试
  • 生成报告

maven 插件 的应用

  • clean 清理
  • prepare-agent 配置 agent
  • test 执行测试
  • jacoco:report 生成报告
<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.9-SNAPSHOT</version>
    <executions>
        <execution>
            <id>default-prepare-agent</id>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>default-prepare-agent-integration</id>
            <goals>
                <goal>prepare-agent-integration</goal>
            </goals>
        </execution>
        <execution>
            <id>default-report</id>
            <goals>
                <goal>report</goal>
            </goals>
        </execution>
        <execution>
            <id>default-report-integration</id>
            <goals>
                <goal>report-integration</goal>
            </goals>
        </execution>
        <execution>
            <id>default-check</id>
            <goals>
                <goal>check</goal>
            </goals>
            <configuration>
                <rules>
                    <rule>
                        <element>BUNDLE</element>
                        <limits>
                            <limit>
                                <counter>COMPLEXITY</counter>
                                <value>COVEREDRATIO</value>
                                <minimum>0.60</minimum>
                            </limit>
                        </limits>
                    </rule>
                </rules>
            </configuration>
        </execution>
    </executions>
</plugin>

mvn 命令

mvn clean test jacoco:report
mvn clean jacoco:prepare-agent test jacoco:report

#不依赖jacoco插件安装
mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent test org.jacoco:jacoco-maven-plugin:report
open target/site/jacoco/index.html

简单的 maven 项目练习

git clone https://github.com/SonarSource/sonar-scanning-examples.git
cd sonar-scanning-examples/sonarqube-scanner-maven/maven-basic
mvn clean test jacoco:report

start.spring.io 项目覆盖率统计练习

cd $START_SPRING_IO_HOME/start-site
mvn clean jacoco:prepare-agent test jacoco:report -Dmaven.gitcommitid.skip=true -Dtest=JavaVersionProjectDescriptionCustomizerTests#java8IsMandatoryMaven
open target/site/jacoco/index.html

#不依赖jacoco插件安装
mvn clean org.jacoco:jacoco-maven-plugin:LATEST:prepare-agent test org.jacoco:jacoco-maven-plugin:LATEST:report -Dmaven.gitcommitid.skip=true -Dtest=JavaVersionProjectDescriptionCustomizerTests#java8IsMandatoryMaven
open target/site/jacoco/index.html

gradle 项目 Jacoco 插件

  • clean 清理
  • build 构建并执行测试
  • jacocoTestReport 生成测试报告
plugins {
    id "jacoco"
}

jacocoTestReport {
    reports {
        xml.enabled true
    }
}

gradle 执行测试获取覆盖率

git clone https://github.com/SonarSource/sonar-scanning-examples.git
cd sonar-scanning-examples/sonarqube-scanner-gradle/gradle-basic
./gradlew clean build jacocoTestReport
open build/reports/jacoco/test/html/index.html

通过 maven 与 gradle 的项目配置例子,相信大家已经知道了如何在正式的项目中应用了,快用起来吧

覆盖率测试实战

Pet clinic 实战

  • 编译打包
  • 单元测试
  • 覆盖率统计
  • sonarqube 分析

start.spring.io 覆盖率实战

  • 编译打包
  • javaagent on the fly 插桩
  • 覆盖率统计
  • 手工测试结合覆盖率
  • 自动化测试与覆盖率