如何用好Go的测试黑科技
测试是每一个开发人员都需要掌握的技能,尽管你不需要像测试人员那么专业,但你也应该尽可能的做到那么专业,据我了解到我身边的一些Go开发人员,他们对Go的测试仅仅局限于写一个_test.go 测试文件,对执行方法进行测试,然后在goland的Ide中右键run方法运行,观测结果是否为绿色,仅此而已,我想说的是这只是一些皮毛,所以今天分享一些Go的测试技能,希望大家有收获。
Go测试用例
Go的测试文件命名规则为xxx_test.go
,其中xxx是需要测试的源代码文件的名称。在test文件中,可以编写测试函数,Go的测试函数整理分为4种,如下,其中XXX是需要测试的方法名称
- 单元测试:TestXXX(t *testing.T)
- 基准测试:BenchmarkXXX(b *testing.B)
- Main函数测试:TestMain(m *testing.M)
- 控制台测试 ExampleXXX()
假设我们有一个array_utils.go
的源代码文件,包名为array_utils
,我们在该包创建一个测试文件,名称为:array_utils_test.go
文件,源代码文件中有一个求最大子序列和的方法,我们针对该方法测试,如下代码,_test.go文件中可以有任意多个测试方法,这些测试方法的合集被称作测试套件。
我们的源码文件如下:
package array_utils
//求最大子序列和 (就是说子序列加起来和最大)
func FindMaxSeqSum(array []int) int {
SeqSum := make([]int, 0) // 存储子序列和
// 初始子序列和为 数组下标为0的值
SeqSum = append(SeqSum, array[0])
for i := 1; i < len(array); i++ {
if array[i] > SeqSum[i-1]+array[i] {
SeqSum = append(SeqSum, array[i])
} else {
SeqSum = append(SeqSum, SeqSum[i-1]+array[i])
}
}
max := SeqSum[0]
for j := 1; j < len(SeqSum); j++ {
if SeqSum[j] > SeqSum[j-1] {
max = SeqSum[j]
}
}
fmt.Println(max) //打印结果
return max
}
我们的测试文件如下
package array_utils
import (
"fmt"
"os"
"testing"
)
//TestMain会在下面所有测试方法执行开始前先执行,一般用于初始化资源和执行完后释放资源
func TestMain(m *testing.M) {
fmt.Println("初始化资源")
result := m.Run() //运行go的测试,相当于调用main方法
fmt.Println("释放资源")
os.Exit(result) //退出程序
}
//单元测试
func TestFindMaxSeqSum(t *testing.T) {
sum := FindMaxSeqSum([]int{1, 3, -9, 6, 8, -19})
if sum == 14 {
t.Log("successful")
} else {
t.Error("failed")
}
}
//基准测试
func BenchmarkFindMaxSeqSum(b *testing.B) {
for i := 0; i < b.N; i++ {
FindMaxSeqSum([]int{1, 3, -9, 6, 8, -19})
}
}
//这个验证的是FindMaxSeqSum方法控制台输出的max和OutPut后面的14是否一致,如果相同,则表示验证通过,否则测试用例失败
func ExampleFindMaxSeqSum() {
FindMaxSeqSum([]int{1, 3, -9, 6, 8, -19})
// OutPut: 14
}
我们通过命令go test来运行这段测试代码,进入到array_utils包下面,go test会遍历当前包下所有的xxx_test.go
中符合上述命名规则的函数,然后生成一个临时的main包用于调用相应的测试函数,然后构建并运行、报告测试结果,最后清理测试中生成的临时文件,结果如下:
初始化资源
=== RUN TestFindMaxSeqSum
14
--- PASS: TestFindMaxSeqSum (0.00s)
array_utils_test.go:16: successful
PASS
释放资源
Go test 有两种运行模式
本地目录模式,在没有包参数(例如 go test 或 go test -v )调用时发生。在此模式下, go test 编译当前目录中找到的包和测试,然后运行测试二进制文件。在这种模式下,caching 是禁用的。在包测试完成后,go test 打印一个概要行,显示测试状态、包名和运行时间
- go test 当软件包属于$GOPATH时,不需要从 Go Module 内部执行此命令,就进行测试
包列表模式,在使用显示包参数调用 go test 时发生(例如 go test math , go test ./... 甚至是 go test .)。在此模式下,Go测试编译并测试在命令上列出的每个包。如果一个包测试通过, go test 只打印最终的 ok 总结行。如果一个包测试失败, go test 将输出完整的测试输出。如果使用 -bench 或 -v 标志,则 go test 会输出完整的输出,甚至是通过包测试,以显示所请求的基准测试结果或详细日志记录
- go test math ,指的是测试Go的SDK的math包中的test文件
- go test ./... , 指的是测试递归测试当前目录下的所有test文件,因为当前目录下还有还有子文件夹,子文件夹下面还有子文件夹。
- go test . 测试当前目录中的软件包
- go test ./tranform 来测试 ./tranform 目录中的包
在包列表模式下,Go缓存成功的测试结果,以避免重复运行相同的测试。每当 GO 在包上运行测试时,Go都会创建一个测试二进制文件并运行它,如果要全局禁用缓存,可以将GOCACHE环境变量设置为off,
set GOCACHE=off //关闭,go1.12版本后必须打开,否则编译器报错
set GOCACHE=on //开启
go clean -testcache //手动清除缓存
Go的test常用参数实践
上面我们只是执行了go test的命令,关于go test可能的flag还有很多,不同的flag其对应的功能不同,接下来我们来实践一下。
基础功能参数
go test -c 生成用于运行测试的可执行文件,但不执行,在window平台下生成的是.exe文件,截图如下
go test -i 安装/重新安装运行测试所需的依赖包,但不编译和运行测试代码。
go test -o array_utils.test.exe 运行指定的的可执行的测试文件
go test -v 输出打印有关测试函数的其它信息
go test -v array_utils_test.go array_utils.go 测试指定的的文件
go test -v array_utils_test.go array_utils.go -test.run TestFindMaxSeqSum 测试指定文件的指定方法
go test -v -run=TestFindMaxSeqSum 测试指定文件的指定方法,-run后面可以匹配正则表达式,这个指的是测试名字等于TestFindMaxSeqSum的方法,如果是多个方法的话,可以使用|来隔开方法名。
代码覆盖率
由单元测试的代码,触发运行到的被测试代码的代码行数占所有代码行数的比例,被称为测试覆盖率,代码覆盖率不一定完全精准,但是可以作为参考,可以帮我们测量和我们预计的覆盖率之间的差距
go test -cover 生成代码测试覆盖率 ,coverage: 8.1% of statements
go test -v -coverprofile=c.out 将生成的代码测试覆盖率放入一个文件,然后运行下面的命令可以将c.out文件转换成一个html文件用浏览器阅读,截图如下,no coverage 代表没有覆盖的代码,high coverage代表高覆盖率的代表,一个红色,一个绿色,这里红色的截图上没体现出来,大家可本地试验一下。
go tool cover -html=c.out -o=tag.html
go test -covermode=set 覆盖测试模式,有三种值set,count,atomic,其中set代表的是这个语句运行吗?count代表的是这个语句执行多少次,atomic代表的是多线程正确使用的,耗资源的。
基准测试
go test默认情况下只会运行单元测试,那么基准测试如何执行呢?接下来一起看看。
go test -bench=. 执行当前测试包下的基准测试方法,在执行过程中会根据实际case的执行时间是否稳定会增加b.N的次数,要注意如果是要测试一个非稳态的函数,那么它可能永远也执行不完,记住-bench后面跟的是正则表达式
这是执行结果,-8指的是运行时对应的 GOMAXPROCS 的值,5000000指的是for循环的次数,249 ns/op 指的是每一次循环耗时239纳秒
BenchmarkFindMaxSeqSum-8 5000000 249 ns/op
go test -run=none -bench=. 通过指定方法名称为none来过滤掉单元测试,只执行基准测试的方法,当然也可以根据-bench后面的正则表达式来匹配。
go test -benchtime=3s -bench=. 在持续时间3s内运行每个基准测试
go test -benchmem -bench=. 打印基准测试时的内存分配
120 B/op代表每次操作消耗120B内存(1kb=1024b), 4 allocs/op 代表每次操作分配内存的次数
BenchmarkFindMaxSeqSum-8 5000000 300 ns/op 120 B/op 4 allocs/op
go test -count=2 -bench=. 执行指定次数的基准测试,在-count=1时相当于禁用缓存
go test -cpu=1 -bench=. 设置指定的cpu数量来进行基准测试,可以指定多个不同的cpu个数列别,比如:-cpu=1,2,4
其它一些参数控制
go test -timeout=3s默认情况下,测试执行超过10分钟就会超时而退出,我们可以通过这个时间指定超时时间
go test -parallel=2 当测试使用t.Parallel()方法将测试转为并发时,将受到最大并发数的限制,默认情况下最多有GOMAXPROCS个测试并发,其他的测试只能阻塞等待,这个可以用来并发安全的测试。
go test -short 缩短长时间运行的测试的测试时间。默认关闭
go test -v -cpuprofile=cpuprof.out 生成cpuprof的文件,通过运行下面的命令可以查看cpuprof的文件,默认是在控制台查看,当然也可以web界面查看,这不是本篇文章的重点,后面会单说。
go tool pprof prof.out
go test -trace trace.out 在退出之前,将执行跟踪写入指定文件。
go test -race 检测并发情况下数据竞争的问题,这个的使用比较复杂,后面也会单写文章来介绍。
testing 的变量
test.short : 一个快速测试的标记,在测试用例中可以使用 testing.Short() 来绕开一些测试
test.outputdir : 输出目录
test.coverprofile : 测试覆盖率参数,指定输出文件
test.run : 指定正则来运行某个 / 某些测试用例
test.memprofile : 内存分析参数,指定输出文件
test.memprofilerate : 内存分析参数,内存分析的抽样率
test.cpuprofile : cpu 分析输出参数,为空则不做 cpu 分析
test.blockprofile : 阻塞事件的分析参数,指定输出文件
test.blockprofilerate : 阻塞事件的分析参数,指定抽样频率
test.timeout : 超时时间
test.cpu : 指定 cpu 数量
test.parallel : 指定运行测试用例的并行数
还有很多,需要读者们自行研究,总结,分享,可以留言区讨论
testing.T 和 testing.B
testing 包内的结构
B : 压力测试
BenchmarkResult : 压力测试结果
Cover : 代码覆盖率相关结构体
CoverBlock : 代码覆盖率相关结构体
InternalBenchmark : 内部使用的结构
InternalExample : 内部使用的结构
InternalTest : 内部使用的结构
M : main 测试使用的结构
PB : Parallel benchmarks 并行测试使用结果
T : 普通测试用例
TB : 测试用例的接口
testing包的方法
如果有帮助,关注下公众号,阅读更多精彩文章

如何用好Go的测试黑科技的更多相关文章
- MTSC2019-腾讯WeTest独家揭秘移动游戏测试和质量保障 QA 黑科技
WeTest 导读 TesterHome 联合腾讯 WeTest 出品 MTSC2019 重磅游戏测试 Topic ,首次公开揭秘腾讯亿级用户游戏背后的质量保障 QA 黑科技. 2019 年,中国游戏 ...
- localStorage的黑科技-js和css缓存机制
一.发现黑科技的起因 今天在微信公众号看到一篇技术博文,想用印象笔记收藏,所以发送了文章链接到pc上.然后习惯性地打开控制台,看看源码,想了解下最近微信用了什么新技术. 呵呵,以下勾起了我侦探的欲 ...
- 基于Twitter的Snowflake算法实现分布式高效有序ID生产黑科技(无懈可击)
参考美团文档:https://tech.meituan.com/2017/04/21/mt-leaf.html Twitter-Snowflake算法产生的背景相当简单,为了满足Twitter每秒上万 ...
- Sublime 黑科技之——lorem快速输入
需要一段文字填充某块演示的空间,但不管写什么文字都觉得不合适,那么这个黑科技你值的拥有. 在Sublime Text中,输入lorem,再按Tab键,即可快速输入一段无意义的占位字符: Lorem i ...
- 【转载】史上最全:TensorFlow 好玩的技术、应用和你不知道的黑科技
[导读]TensorFlow 在 2015 年年底一出现就受到了极大的关注,经过一年多的发展,已经成为了在机器学习.深度学习项目中最受欢迎的框架之一.自发布以来,TensorFlow 不断在完善并增加 ...
- 这些JavaScript编程黑科技
1.单行写一个评级组件 "★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate);定义一个变量rate是1到5的值,然后执行上面代码,看图 才发现插件什么的都 ...
- 推荐一个以动画效果显示github提交记录的黑科技工具:Gource
程序员每天都会使用到git的一系列命令.其中用git log命令可以查看提交历史记录: 今天Jerry给大家推荐一款视觉效果非常酷炫的工具,名叫Gource,是一个能够将git代码仓库的提交历史以动画 ...
- qt的应用层主要是大型3d,vr,管理软件和器械嵌入软件(有上千个下一代软件黑科技项目是qt的,美国宇航局,欧洲宇航局,超级战舰DDG1000)
作者:Nebula.Trek链接:https://www.zhihu.com/question/24316868/answer/118944490来源:知乎著作权归作者所有.商业转载请联系作者获得授权 ...
- Python黑科技:6行代码轻松搭建FTP服务器
Python 黑科技 六行代码轻松搭建个人FTP服务器 什么是FTP服务器? FTP (File Transfer Protocol) 是一个用于客户端与服务器之间文件的协议.利用FTP我们就能做到在 ...
随机推荐
- python基础八之文件操作
python的文件操作 1,打开文件 编码方式要和文件的编码方式相同! #open('路径','打开方式','指定编码方式') f = open(r'E:\pycharm\学习\day8\test', ...
- 2019-4-6-VisualStudio-2019-如何离线下载
title author date CreateTime categories VisualStudio 2019 如何离线下载 lindexi 2019-04-06 09:26:11 +0800 2 ...
- 如何在centos 7.4 上安装 python 3.6
yum -y install https://centos7.iuscommunity.org/ius-release.rpmyum -y install python36uyum -y instal ...
- NetBIOS 计算机名称命名限制
本文告诉大家对于 NetBIOS 的命名的限制 长度限制 最小长度是 1 最长长度是 15 因为默认是 16 字符,但是微软使用最后一个字符作为后缀 可以使用的字符 可以使用英文和数字 abcdefg ...
- 【38.96%】【hdu 1540】Tunnel Warfare
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission ...
- classpath*与classpath
classpath*:的出现是为了从多个jar文件中加载相同的文件. classpath:只能加载找到的第一个文件.
- import()函数
简介 import命令会被 JavaScript 引擎静态分析,先于模块内的其他模块执行(叫做”连接“更合适).所以,下面的代码会报错. // 报错 if (x === 2) { import MyM ...
- gitLab操作规范和项目流程
刚做完一个项目并且艰难得上线,对整个项目流程和gitLab规范 有了一些心得,给新来的同学普及一下. 最先产品会写一篇需求文档,咱们要先看需求文档对项目有一个大致了解,然后产品喊后端.ui.前端 一 ...
- windows下使用cmake+mingw配置makefile
前面一节说了cmake简易使用,但是实际开发中项目文件非常多,使用哪种简易方式会导致代码十分混乱,因此本文介绍一种cmake管理大型项目的demo流程. 具体步骤如下: 1.创建相关的项目目录 cmd ...
- Java中的Redis 哨兵高可用性
让我们探索Redis Sentinel,看看如何在Java上运行它,一起来看看,最近get了很多新知识,分享给大家参考学习.需要详细的java架构思维导图路线也可以评论获取! 什么是Redis哨兵? ...