前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >golang源码分析:单测和集成测试覆盖率实现原理(1)

golang源码分析:单测和集成测试覆盖率实现原理(1)

作者头像
golangLeetcode
发布2023-03-01 16:20:31
1.1K1
发布2023-03-01 16:20:31
举报

在了解集成测试覆盖率实现原理之前,先看看单测覆盖率是如何实现的:go语言采用的是插桩源码的形式,而不是待二进制执行时再去设置breakpoints。这就导致了当前go的测试覆盖率收集技术,一定是侵入式的,会修改目标程序源码。对于下面一段代码

代码语言:javascript
复制
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")
}

我们运行命令

代码语言:javascript
复制
 go tool cover -mode=count -var=CoverageVariableName learn/cover/exp1/main.go >> learn/cover/exp1/main_gen.go

可以看到生成的代码如下

代码语言:javascript
复制
//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 {
  Cou     [6]uint32
  Pos     [3 * 6]uint32
  umStmt   [6]uint16
} {
  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
  },
}

可以看到,生成了一个结构体,它有三个元素,每个元素都是一个数组。在源码的每一个逻辑分支开始的地方,都会对计数Count进行累加。

CoverageVariableName变量,其有三个比较关键的属性:

  1. `Count` uint32数组,数组中每个元素代表相应基本块(basic block)被执行到的次数
  2. `Pos` 代表的各个基本块在源码文件中的位置,三个为一组。比如这里的`21`代表该基本块的起始行数,`23`代表结束行数,`0x2000d`比较有趣,其前16位代表结束列数,后16位代表起始列数。通过行和列能唯一确定一个点,而通过起始点和结束点,就能精确表达某基本块在源码文件中的物理范围
  3. `NumStmt` 代表相应基本块范围内有多少语句(statement)

可以看到,通过打点和运行时计数累加的方式就可以知道了每一个代码块是不是被执行了,执行了多少次。依托这个go官方的工具链就可以知道,哪些代码被执行了,执行了多少次。

对于集成测试,go官方并没有给出很好用的工具,但是基于上述原理,我们很容易想到,我们可不可以用go tool cover工具在我们原有的代码上插入上述桩代码,然后,部署有桩代码的版本,集成测试的时候,我们累计代码被执行的次数,就可以很好分析集成测试的覆盖率了。

https://github.com/qiniu/goc正是基于上述原理实现的集成测试覆盖率分析工具。如何使用呢,首先安装:

代码语言:javascript
复制
curl -s https://api.github.com/repos/qiniu/goc/releases/latest | grep "browser_download_url.*-darwin-amd64.tar.gz" | cut -d : -f 2,3 | tr -d \" | xargs -n 1 curl -L | tar -zx && chmod +x goc && mv goc /usr/local/bin

然后我们下载官方的制定的样例包

代码语言:javascript
复制
git submodule add https://github.com/enricofoltran/simple-go-server

使用goc启动一个服务注册中心,后面就可以到这个注册中心查询覆盖率

代码语言:javascript
复制
1,use goc server to start a service registry center:
 ✗ goc server

第二步就是用goc工具编译生成带桩的二进制程序,然后启动我们的程序提供服务

代码语言:javascript
复制
 2,use goc build to build the target service, and run the generated binary.
 ✗ goc build .
  ✗ ./simple-go-server  

第三步就是查询我们的代码覆盖率结果

代码语言:javascript
复制
 3,use goc profile to get the code coverage profile of the started simple server above
 ✗ goc profile
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-02-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
微服务引擎 TSE
微服务引擎(Tencent Cloud Service Engine)提供开箱即用的云上全场景微服务解决方案。支持开源增强的云原生注册配置中心(Zookeeper、Nacos 和 Apollo),北极星网格(腾讯自研并开源的 PolarisMesh)、云原生 API 网关(Kong)以及微服务应用托管的弹性微服务平台。微服务引擎完全兼容开源版本的使用方式,在功能、可用性和可运维性等多个方面进行增强。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档