go/java/C++覆盖率工具原理汇总学习记录

这篇具有很好参考价值的文章主要介绍了go/java/C++覆盖率工具原理汇总学习记录。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

go–goc

goc采用的是插桩源码的形式,而不是待二进制执行时再去设置breakpoints。这就导致了当前go的测试覆盖率收集技术,一定是侵入式的,会修改目标程序源码。直接看案例

package main

import "fmt"

func main() {
  test2(3)
  fmt.Println("main")
  test2(-3)
}

func test1() {
  fmt.Println("hello")
  fmt.Println("test1")
}

func test2(a int) {
  if a > 0 {
    fmt.Println(a)
    test1()
  } else {
    fmt.Println("world")
  }
  fmt.Println("test2")
}

运行命令

 go tool cover -mode=count -var=CoverageVariableName learn/cover/exp1/main.go >> learn/cover/exp1/main_gen.go

生成的代码如下

//line learn/cover/exp2/main.go:1
package main

import "fmt"

  
func main() {CoverageVariableName.Count[0]++;
  test2(3)
  fmt.Println("main")
  test2(-3)
}

  
func test1() {CoverageVariableName.Count[1]++;
  fmt.Println("hello")
  fmt.Println("test1")
}

  
func test2(
    a int) {CoverageVariableName.Cont[2]++;
  if a > 0 {CoverageVariableName.Count[4]++;
    fmt.Println(a)
    test1 (
    CoverageVariableName.Count[5]++
    
    } else{ CoverageVariableName.Count[5]++;{
      
  fmt.Println("world")
  }}
  
  CoverageVariableName.Count[3]++;fmt.Println("test2")
}

var CorageVariableName = struct {
  Count     [6]uint32     //数组中每个元素代表相应基本块(basic block)被执行到的次数
  Pos     [3 * 6]uint32     // 代表的各个基本块在源码文件中的位置,三个为一组。比如这里的`21`代表该基本块的起始行数,`23`代表结束行数,`0x2000d`比较有趣,其前16位代表结束列数,后16位代表起始列数。通过行和列能唯一确定一个点,而通过起始点和结束点,就能精确表达某基本块在源码文件中的物理范围
  NumStmt   [6]uint16   // 代表相应基本块范围内有多少语句(statement)
} {
  Pos: [3 * 6]uint32{
    5, 9, 0x2000d, // [0]
    11, 14, 0x2000e, // [1]
    16, 17, 0xb0013, // [2]
    23, 23, 0x160002, // [3]
    17, 20, 0x3000b, // [4]
    20, 22, 0x30008, // [5]
  },
  NumStmt: [6]uint16{
    3, // 0
    2, // 1
    1, // 2
    1, // 3
    2, // 4
    1, // 5
  },
}

java-jacoco

jacoco是一个开源的代码覆盖率工具,针对java语言,其使用方法很灵活,可以嵌入到Ant、Maven中;可以作为Eclipse插件,可以使用其JavaAgent技术监控Java程序等等。

java 代码运行原理

java代码是运行在java虚拟机(JVM)上的,JVM相当于一个虚拟的计算机,符合约定的指令均可在上面执行。java编译后的class文件就是一种符合JVM的字节码指令集合,所以可以在JVM上执行。所以JVM其实指的不是运行java代码的虚拟机,它并不关心字节码是由哪种语言编译而来的,而是只要符合该虚拟机指令的文件均可在上面执行,如Kotlin、Groovy、JRuby、Jython、Scala等编译后也可以在JVM上执行。所以java代码在JVM里运行的时候,实际运行的是编译后的class文件字节码指令流,如果想要改变类的行为,分析类的信息等,只需要修改对应的字节码即可

jacoco原理

jacoco即是通过修改class文件的字节码来进行代码覆盖率统计的。即,在原有class字节码中的指定位置插入探针字节码,形成新的字节码指令流。jacoco使用的是ASM字节码框架对字节码进行修改的。jacoco的探针实际是一个布尔值,当代码执行到探针位置时,将其置为true,该探针前面的代码会被认为执行过,然后对该部分代码对应的html文件中的css样式进行染色(红色表示未覆盖,绿色表示已覆盖,黄色表示部分覆盖),形成最终的覆盖率报告

jacoco插庄模式(插入探针)

  • offline模式:编译时插桩,在测试前先对文件进行插桩,然后生成插过桩的class或jar包,测试插过桩 的class和jar包后,会生成动态覆盖信息到文件,最后统一对覆盖信息进行处理,并生成报告。

  • on-the-fly模式:运行时插桩,JVM中通过-javaagent参数指定特定的jar文件启动Instrumentation的代理程序,启动jvm实例会调用程序里面的premain方法,通过Class Loader装载一个class前判断是否转换修改class文件,将统计代码插入class,测试覆盖率分析可以在JVM执行测试代码的过程中完成。addTransformer 方法并没有指明要转换哪个类,转换发生在 premain 函数执行之后,main 函数执行之前(转换发生在JVM定义类之前),这时每装载一个类,transform 方法就会执行一次,看看是否需要转换。

插庄对比

go/java/C++覆盖率工具原理汇总学习记录

C+±gcov

gcov是gcc内置的一个代码覆盖率工具,配合GCC共同实现对C/C++文件的语句覆盖、功能函数覆盖和分支覆盖测试,通常需要结合lcov生成可视化报告。
go/java/C++覆盖率工具原理汇总学习记录

工作流

  1. 编译前,在编译器中加入编译器参数-fprofile-arcs -ftest-coverage;
  2. 源码经过编译预处理,然后编译成汇编文件,在生成汇编文件的同时完成插桩。插桩是在生成汇编文件的阶段完成的,因此插桩是汇编时候的插桩,每个桩点插入3~4条汇编语句,直接插入生成的*.s文件中,最后汇编文件汇编生成目标文件,生成可执行文件;并且生成关联BB和ARC的.gcno文件;
  3. 执行可执行文件,在运行过程中之前插入桩点负责收集程序的执行信息。所谓桩点,其实就是一个变量,内存中的一个格子,对应的代码执行一次,则其值增加一次;
  4. 生成.gcda文件,其中有BB和ARC的执行统计次数等,由此经过加工可得到覆盖率。

配置使用

gcc -fprofile-arcs -ftest-coverage -o test test.c

-ftest-coverage:在编译时产生.gcno文件,它包含了重建基本块图和相应的块的源码的行号信息*

-fprofile-arcs :在运行编译过的程序,会产生.gcda文件,包含基本块弧跳变的次数信息
Gcc在编译阶段指定 –ftest-coverage 等覆盖率测试选项后,GCC会:
1、 在输出目标文件中留出一段存储区保存统计数据;

2、 在源代码中每行可执行语句生成的代码之后附加一段更新覆盖率统计结果的代码,也就是插桩(后面详细介绍);

3、 Gcc编译,会生成*.gcno文件,它包含重建基本块图和相应块的源码的行号信息;

4、 在最终可执行文件中,进入main函数之前调用gcov_init内部函数初始化统计数据区,并将gcov_init内部函数注册为exit_handers,用户代码调用exit正常结束时,gcov_exit函数得到调用,并继续调用__gcov_flush输出统计数据到*.gcda文件

插庄

gcov是使用 基本块BB 和 跳转ARC 计数,结合程序流图来实现代码覆盖率统计的
基本块BB:如果一段程序的第一条语句被执行过一次,这段程序中的每一个都要执行一次,称为基本块。一个BB中的所有语句的执行次数一定是相同的。一般由多个顺序执行语句后边跟一个跳转语句组成。所以一般情况下BB的最后一条语句一定是一个跳转语句,跳转的目的地是另外一个BB的第一条语句,如果跳转时有条件的,就产生了分支,该BB就有两个BB作为目的地。

跳转ARC:从一个BB到另外一个BB的跳转叫做一个arc,要想知道程序中的每个语句和分支的执行次数,就必须知道每个BB和ARC的执行次数。

如果把BB作为一个节点,这样一个函数中的所有BB就构成了一个有向图。要想知道程序中的每个语句和分支的执行次数,就必须知道每个BB和ARC的执行次数。根据图论可以知道有向图中BB的入度和出度是相同的,所以只要知道了部分的BB或者ARC大小,就可以推断所有的大小。
go/java/C++覆盖率工具原理汇总学习记录

由ARC的执行次数来推断BB的执行次数。所以对部分 ARC插桩,只要满足可以统计出来所有的BB和ARC的执行次数即可。

记录BB块和ARB的数据结构为:

struct bb

{

long zero_word; //是否被插入到链表中

const char *file_name; //当前被测试文件名

long *count;//指向bx2的指针

long ncounts;//桩点个数

struct bb *next;//下一个文件的BX2信息

};

1、GCC在插桩的过程中会向源文件的末尾插入一个静态数组,BX2.,数组的大小就是这个源文件中桩点的个数。BX2+0代表第0个桩点的位置,BX2+n代表第n个桩点的位置,数组的值就是桩点的执行次数。

2、每个桩点插入汇编语句:

*按照我的理解,汇编语句是inc$(BX2+n).

3、 BX2数组链表:

为了便于统计,gcc还将各个源文件中的BX2数组链接成一个链表,这个链表结构是在测试main函数之前就产生了,在调用main之前会有一个类似构造函数的函数,进行构建链表。这个函数会在退出时调用exit函数计算执行次数生成.gcda文件文章来源地址https://www.toymoban.com/news/detail-423230.html

到了这里,关于go/java/C++覆盖率工具原理汇总学习记录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 如何有效保证Java代码单元测试覆盖率

    我们在实际项目开发过程中,不同level的童鞋由于专业技能的层次不同,导致在参与实际开发的业务代码中经常会出现各种bug,项目管理中好的pm或许会给充足的时间来让开发童鞋们定位修复这些bug,也有各种客观原因的PM不会在项目中预留这些时间,往往就需要开发自己通过

    2023年04月17日
    浏览(49)
  • UVM学习笔记1——断言和断言覆盖率

    2023.3.8 一直都没懂覆盖率和断言,今天开始慢慢学 2023.3.11 打卡学习 2023.4.4 断言不仅可以进行 时序的检测 ,还可以进行 覆盖率的收集 ,因为covergroup只适合对功能点的测试,但是信号与信号之间的时序是否正确可能不能很好的覆盖,使用断言更加方便。 用来与设计功能和时

    2024年02月09日
    浏览(37)
  • 16 RTL仿真工具介绍—Modelsim脚本操作(Modelsim仿真 覆盖率测试)

    深入还是得靠自己学——尤其是脚本代码的编写 目录 1.Flist常用写法 2.Debussy——检查语法错误+debug代码 2.Linux版的Debussy——verdi 3.Modelsim——do file脚本 4.按脚本方式操作Modelsim 1.首先更改工作目录,到Modelsim文件夹下 2.写脚本代码 3.执行脚本、仿真 4.加载波形、界面操作、保存

    2024年02月08日
    浏览(56)
  • 使用 【jacoco】对基于 SpringBoot 和 Dubbo RPC 的项目生成测试覆盖率报告:实践+原理

    基于 Dubbo RPC 的项目中有一个提供者项目backend、一个消费者项目gateway、以及注册中心nacos。本篇文章记录在windows本地对该框架的测试过程,以及介绍jacoco的基本原理 官网下载安装包解压到本地,https://www.jacoco.org/jacoco/ 只需要用到jacoco/lib 文件夹中的 jacocoagent.jar 以及jacococl

    2024年02月09日
    浏览(40)
  • java & jacoco & powerMock 单元测试覆盖率为0怎么解决

    我们项目中使用powerMock作为单元测试的mock工具,统计项目测试覆盖率使用jacoco编译的结果上传到sonar,但是jacoco 和 powerMock在运行时runtime加载代码的时候自定义了类加载器,所以就会有冲突,导致测试覆盖率为0。 使用命令 mvn clean verify sonar:sonar上传jacoco编译结果(这里sonar命令

    2023年04月08日
    浏览(45)
  • Idea coverage覆盖率测试工具,设置Coverge的Branch,以及生成测试报告遇到的问题

    1、打开Run/Debug Configurations 2、选中该工程的项目() 3、选择以coverge runner结尾的选项,不同版本可能不同 第一种版本: 第二种版本 4、设置branch 可以看到Code Coverge出现了。 选择JaCoCo 5、选择Use tracing 可以看到生成Branch选项了。 1、选择导出 2、选项(根据需要设置) 注意点 :Re

    2024年02月05日
    浏览(44)
  • sonar覆盖率、代码覆盖率、分支覆盖率的计算方式

    代码质量的覆盖率分为三种,覆盖率、代码覆盖率、分支覆盖率,那每一种的计算方式是怎么样的呢? 举例: 上面最有疑惑的是覆盖率,不知道怎么算出了来的,后面再说。 通过sonarqube可以分析出: 指标 值 可覆盖行(lines_to_cover) 13242 未覆盖的代码(uncovered_lines) 7943 可

    2024年02月06日
    浏览(44)
  • (十四)覆盖率类型、覆盖率组

    覆盖率是用来衡量设计验证完备性。 随着测试逐步覆盖各种合理的组合,覆盖率用来衡量测试进行的程度。 覆盖率工具会在仿真过程中收集信息,然后进行后续处理并且得到 覆盖率报告。 通过报告找出覆盖盲区,然后修改现有test或者创建新的test来填补这些盲区。 这个过程

    2024年02月09日
    浏览(32)
  • 代码覆盖率

    在做单元测试时,代码覆盖率常常被拿来作为衡量测试好坏的指标,甚至,用代码覆盖率来考核测试任务完成情况,比如,代码覆盖率必须达到80%或 90%。于是乎,测试人员费尽心思设计案例覆盖代码。用代码覆盖率来衡量,有利也有有弊。本文我们就代码覆盖率展开讨论

    2024年02月07日
    浏览(34)
  • 如何计算单元测试的覆盖率

    单元测试的覆盖率有:语句覆盖率(即行覆盖率)、分支覆盖率、条件覆盖率、分支条件覆盖率、路径覆盖率等。 语句覆盖率 所谓语句就是那些非分支、非判断的语句。 计算公式:程序执行到的语句总数 / 全部语句的总数 分支覆盖率 有判定语句的地方都会出现2个分支。

    2024年01月21日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包