- Go 的测试方法依赖于命令 go test 和一些能用 go test 运行的测试函数的编写约定。编写测试用例和编写常规的 Go 代码没有区别。
-
在一个包目录中,以 _test.go 结尾的文件由 go test 命令编译
-
*_test.go 文件中有三种特殊函数:
-
以 Test 前缀命名的函数:检测程序逻辑的正确性,go test 运行测试函数并提供报告
-
以 Benchmar 开头的函数:测试操作的性能,go test 汇报操作的评价执行时间
-
以 Example 开头的函数: 用来提供机器检查过的文档
-
-
测试函数的签名必须如下。 testing.T 提供了汇报测试结果和日志记录功能,参考 go doc
import testing func TestName(t *testing.T) { // ... }
-
给 go test 加上 -run="正则表达式" 运行名称匹配的测试函数,或者运行某个测试函数
-
可以把多个测试用例的输入和结果放到一个表里:
func TestCase(t *testing.T) { var tests = []struct { input string want bool }{ {"", true}, {"a",true}, } for _, test := range tests { //... } }
-
用t.Error输出错误,一般格式是 f(x)=y, want z
-
使用 t.Fatal 或 t.Fatalf 函数来终止测试
-
编写一个辅助函数返回一个随机输出作为被测试函数的输入
-
测试函数中反复调用辅助函数得到输入来测试
-
将 _test.go 文件声明为 main 包,测试函数调用被测试函数。
-
go test 命令不会执行 main() 函数
-
白盒测试通过把测试函数放入被测函数的包内,共享包全局变量和函数
-
在测试用例中,重新赋值全局变量和函数变量绕开真正的操作
-
在测试用例开始时保存被修改的变量值,用defer在测试结束时还原被修改的变量
-
为了避免循环引用,使用外部测试包来测试有循环依赖的两个包
-
在包内的 export_test.go 测试文件中添加函数声明,将内部的功能暴露给外部测试。
-
在编写测试函数时应避免过早抽象
-
一个好的测试应首先实现所期望的具体行为,并仅在这个时候再使用工具函数来使代码简洁并避免重复。
-
仅检查关心的属性来避免写出脆弱的测试
-
值得写出一个稳定的函数来从复杂的输出中提取核心内容,否则时间就会被花在修复奇怪失败的测试上
# 运行测试,计算覆盖率
go test -coverprofile=c.out -covermode=count
# 浏览器查看覆盖率结果
go tool cover -html=c.out
-
基准测试函数以 Benchmark 作为前缀,并接收一个 *testing.B 类型的参数。用 b.N 控制循环次数。在 for 循环外围执行测试的初始化工作。
import "testing" func BenchmarkCase(b *testing.B){ for i := 0; i < b.N; i++ { //.. } }
-
go test -bench=. 执行基准测试。-benchmem 记录内存分配统计数据
-
通常统计两个不同操作的相对耗时更有意义:
func benchmark(b *testing.B, size int) { /*...*/} func Benckmark10(b *testing.B) { benchmark(b, 10) } func Benckmark100(b *testing.B) { benchmark(b, 100) } func Benckmark1000(b *testing.B) { benchmark(b, 1000) }
-
go test 加上参数 -cpuprofile, -blockprofile 或 -memprofile
-
go tool pprof 输出报告
- 函数以 Example 作为前缀, 没有参数。可以作为文档示例;通过 go test 的执行;提供手动实验代码