golang之测试testing
01
介绍
我们使用 Golang 语言开发的项目,怎么保证逻辑正确和性能要求呢?也就是说我们如何测试我们的 Golang 代码呢?在 Golang 语言中,可以使用标准库 testing 包编写单元测试和基准测试,使用 go test 命令执行单元测试和基准测试的代码。本文我们介绍在 Golang 语言中怎么编写测试代码。
02
命名规范
在 Golang 语言中编写测试代码,需要遵循一些命名规范,包含文件名、包名、函数(方法)名和变量名。
文件名和包名
测试文件名以 _test.go 结尾,go test 工具可以遍历以 _test.go 结尾的文件,执行测试函数。而 go build 和 go run 会忽略以 _test.go 结尾的文件,文件名开头一般是被测试函数所在的文件名。
包名一般和被测试文件的包名相同,这样即可以测试被测试文件的可导出函数和不可导出函数。
函数名和方法名
测试函数(方法)名必须以 Test、Benchmark 和 Example 开头,并且必须是可导出函数。函数名一般是被测试函数名,首字母大写。如果我们需要给同一个函数编写多个测试函数,可以在函数名后接上测试函数的场景,例如:TestXxxxXxxx。
变量名
测试函数(方法)的变量名,Golang 语言和 go test 工具没有明确的约束,但是,社区针对输出结果有一些规范供大家参考。在编写单元测试代码时,一般会得到一个实际输出结果,和一个我们预期的输出结果做对比。针对这两个变量,社区的变量名规范是 got/want 或 expected/actual。
03
编写测试代码
单元测试
所谓单元测试,顾名思义就是对单元进行测试,一般进行测试的单元是一个最小的单元,在 Golang 语言中,最小的单元就是指一个函数或方法。
单元测试的函数,函数名以 Test 开头,例如:TestXxx。参数必须是 *testing.T 类型,可以使用该类型的方法记录测试信息和测试状态。例如,一般使用 Log 和 Logf 记录测试信息,使用 Error、Errorf、Fatal 和 Fatalf 方法记录测试状态,该类型的更多方法可以阅读官方文档。
被测试函数:
func Sum(a, b int) int {
return a+b
}
测试函数:
func TestSum(t *testing.T) {
a, b := 1,2
rst := Sum(a, b)
if rst == 3 {
t.Logf("expected=%d, actual=%d", 3, rst)
} else {
// t.Errorf("expected=%d, actual=%d", 3, rst)
t.Fatalf("expected=%d, actual=%d", 3, rst)
}
t.Log("done")
}
阅读上面这段代码,是我们编写的 Sum 函数的单元测试,给定 a, b 两个变量作为 Sum 函数的输入参数,此外,我们还可以使用表格测试法,给定一组被测试函数的输入参数,限于篇幅,本文不准备花费篇幅介绍。
使用 go test 命令执行以上单元测试的代码:
go test
PASS
ok learn_go/lesson27 0.555s
go test 命令遍历所有 _test.go 结尾的文件,执行文件中所有的测试函数。此外,go test 支持一些参数,
例如,
-v 输出测试函数的运行详情;
-run 指定执行的测试函数;
-count 指定执行次数。
此外,使用参数 --coverprofile 统计单元测试的覆盖率。
go test --coverprofile=func.cover
PASS
coverage: 100.0% of statements
ok learn_go/lesson27 0.499s
阅读上面的执行结果,可以发现我们编写的单元测试覆盖率为 100%。
如果我们想要查看详细的覆盖率统计结果,我们可以执行以下命令生成 html 文件,使用浏览器打开生成的 html 文件,可以查看详细的单元测试覆盖率统计结果。
go tool cover -html=func.cover -o func_cover.html
运行以上命令,会生成一个名为 func_cover.html 的文件,我们可以使用浏览器打开它,查看详细的单元测试覆盖率统计结果。
基准测试
在 Golang 语言中,可以使用基准测试查看代码的性能。基准测试的函数名以 Benchmark 开头,例如:BenchmarkXxx。参数必须是 *testing.B 类型,函数体中 for 循环的条件,以 b.N 作为循环次数,它是基准测试框架提供的,它在 Golang 运行时动态调整,通过多次测试,得到性能评估结果。
示例代码:
func BenchmarkSum(b *testing.B) {
for i := 0; i < b.N; i++ {
Sum(1, 2)
}
}
我们可以使用 go test 工具执行以上基准测试的代码,基准测试函数不会自动执行,必须使用参数 -bench。
go test -bench=".*"
goos: darwin
goarch: amd64
pkg: learn_go/lesson27
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
BenchmarkSum-16 1000000000 0.2325 ns/op
PASS
ok learn_go/lesson27 0.748s
阅读上面的执行结果,我们主要介绍一下 BenchmarkXxx-n 这一行的意思。这一行共有三列,
第一列 BenchmarkSum-16 分别代表基准测试的函数名和参与基准测试的 CPU 线程数,默认是 GOMAXPROCS 的值。
第二列 1000000000 表示基准测试循环执行的次数。
第三列 0.2325 ns/op 表示每次循环的平均执行耗时是 0.2325 纳秒,该值越小,说明代码性能越高。
除了 b.N 之外,还有几个关于性能测试时间计数的方法,例如:b.ResetTimer()、b.StopTimer() 和 b.StartTimer(),我们可以根据我们的测试场景,灵活使用。
此外,go test 工具关于基准测试的参数,除了参数 -bench 之外,还有
-benchmem 统计内存分配;
-cpu 指定参与执行基准测试的 CPU 线程数;
-benchtime 指定测试时间和循环次数,其中值的单位为 s 表示指定执行多少秒,单位为 x 表示指定循环执行次数;
-timeout 指定基准测试函数执行的超时时间。
b.StopTimer():调用该函数停止压力测试的时间计数
b.StartTimer():重新开始时间
在 b.StopTimer() 和 b.StartTimer() 之间可以做一些准备工作,这样这些时间不影响我们测试函数本身的性能。
04
总结
本文我们介绍怎么编写测试代码,包含单元测试和基准测试。特别需要注意的是一些命名规范。
养成编写测试代码的习惯,不仅可以降低代码逻辑的错误率,而且在多人开发中,还可以提升联调效率和提测通过率。
参考:
golang之测试testing的更多相关文章
- [Golang] GoConvey测试框架使用指南
GoConvey 是一款针对Golang的测试框架,可以管理和运行测试用例,同时提供了丰富的断言函数,并支持很多 Web 界面特性. GoConvey 网站 : http://smartystreet ...
- HoloLens开发手记 - 测试 Testing
测试HoloLens应用的做法和测试Windows应用很类似.所有常规的内容都应该被考虑在内(功能.互操作性.性能.安全性.可靠性等等),然而有些特性是HoloLens特有的,在PC或者手机上无法测试 ...
- Ubuntu下安装Golang并测试HelloWorld
Intel Core i5-8250U,Ubuntu 18.04(安装在虚拟机Oracle VirtualBox 5.2.12上),Go 1.11, 安装步骤如下: -进入Go文档官网: https: ...
- Golang&Python测试thrift
接上篇,安装好之后,就开始编写IDL生成然后测试. 一.生成运行 参考 http://www.aboutyun.com/thread-8916-1-1.html 来个添加,查询. namespace ...
- Golang:测试map是否存在
请看这个url:http://www.du52.com/text.php?id=561 if v, ok := m1["a"]; ok { fmt.Println(v) } els ...
- golang多进程测试代码
package main import ( "fmt" "runtime" ) func test(c chan bool, n int) { x := 0 f ...
- Golang Json测试
结构体是谷歌搜索API package main import ( "encoding/json" "fmt" "io/ioutil" &q ...
- Golang测试包
Golang测试包 golang自带了测试包(testing),直接可以进行单元测试.性能分析.输出结果验证等.简单看着官方文档试了试,总结一下: 目录结构和命令 使用golang的测试包,需要遵循简 ...
- 【Golang】解决Go test执行单个测试文件提示未定义问题
背景 很多人记录过怎么执行Go test单个文件或者单个函数,但是要么对执行单文件用例存在函数或变量引用的场景避而不谈,要么提示调用了其它文件中的模块会报错.其实了解了go test命令的机制之后,这 ...
- <转>年终盘点!2017年超有价值的Golang文章
马上就要进入2018年了,作为年终的盘点,本文列出了一些2017年的关于Go编程的一些文章,并加上简短的介绍. 文章排名不分先后, 文章也不一定完全按照日期来排列.我按照文章的大致内容分了类,便于查找 ...
随机推荐
- c程序设计语言 by K&R(一)一些c语言基础知识
出自<c程序设计语言> by K&R: 一.导言 二.类型.运算符与表达式 三.控制流 1. 字符输入与输出 getchar() 和 putchar(),输入一个字符.输出一个字符 ...
- 使用 Wake Lock API:保持设备唤醒的最佳实践
在现代 Web 应用中,尤其是涉及视频播放.实时通信.地图导航等长时间运行的任务时,用户常常希望设备不要因为空闲而自动进入睡眠模式或屏幕变暗.为了解决这一问题,Web API 提供了一个名为 Wake ...
- Shiro-550—漏洞分析(CVE-2016-4437)
目录 漏洞原理 源码分析 加密过程 解密过程 漏洞复现 漏洞原理 Shiro-550(CVE-2016-4437)反序列化漏洞 在调试cookie加密过程的时候发现开发者将AES-CBC用来加密的密钥 ...
- Windows系统环境变量
添加环境变量: 添加系统变量,机器要重新启动 添加用户变量,机器不用重启: 一般添加环境变量都添加在用户变量中,但只针对这一用户生效 为了使的所有用户都能正常使用软件,通常添加系统变量
- C++的并发编程历史
多线程环境 并非所有的语言都提供了多线程的环境.即便是C++语言,直到C++11标准之前,也是没有多线程支持的. 在这种情况下,Linux/Unix平台下的开发者通常会使用POSIX Threads, ...
- 树形结构数据 数组对象 按照 sort 字段排序
export function sortTreeData (data, flag) { let arr = [] if (flag === 1) { arr = data[0].children } ...
- js中有哪些定时器 , 它们的用法和区别?
js有setInterval() 间隔函数 和 setTimeout()延迟函数 2 种定时器 1. setInterval间隔函数 setInterval() 方法可按照指定的周期(以毫秒计)来调用 ...
- 键盘事件 key keyCode
keyCode 8 = BackSpace BackSpace keyCode 9 = Tab Tab keyCode 12 = Clear keyCode 13 = Enter keyCode 16 ...
- 何为ORM框架?和ADO.NET 对比
百度:ORM(Object Relational Mapping)框架采用元数据来描述对象与关系映射的细节,元数据一般采用XML格式,并且存放在专门的对象一映射文件中.简单理解为一种框架的格式 . 只 ...
- 凌晨 12 点突发 istio 生产事故!一顿操作猛如虎解决了
事故起因 业务上新集群,本来以为"洒洒水",11 点切,12 点就能在家睡觉了.流量切过来后,在验证过程中,发现网页能够正常打开,在登录时返回了 502,当场懵逼.在相关的容器日志 ...