1 Go测试的分类
单元测试
基准测试(性能测试)
子测试与子基准测试
2 测试模式
包列表模式:go test .
测试在命令上列出的每个包。正则匹配方式。
当前目录模式:go test
3 常用参数和示例
这里介绍几个常用的参数:
- -bench regexp 执行相应的 benchmarks,例如 -bench=.
- -cover 开启测试覆盖率;
- -run regexp 只运行 regexp 匹配的函数
- 例如 -run=TestAdd(-run TestAdd) 那么就执行包含有
TestAdd 开头
的函数,'TestAdd$'
代表只执行Array名字的函数 - 参数支持通配符
*
,和部分正则表达式,例如^
、$
。 - -run=none,代表要执行这个名字的函数,如果没有就不执行,也就代表不执行单元测试
- 例如 -run=TestAdd(-run TestAdd) 那么就执行包含有
- -v 显示测试的详细命令。
go test -v
,-v
参数会显示每个用例的测试结果
-benchtime
:可以自定义测试时间
go test
,该 package 下所有的文件的所有测试用例都会被执行。
go test calc_test.go
,运行该 package 下的calc_test.go
文件的所有测试用例。
go test calc_test.go -run=TestAdd
,运行该 package 下的calc_test.go
文件的以TestAdd开头的所有用例。
go test calc_test.go -run='TestAdd$'
,运行该 package 下的calc_test.go
文件的TestAdd用例。
4 测试代码规范
执行 go test
命令,它会在 *_test.go
中寻找 test 测试
、benchmark 基准
和 examples 示例
函数。测试函数必须以 TestXXX
的函数名出现(XXX 为以非小写字母开头),基准函数必须以 BenchmarkXXX
的函数名出现,示例函数必须以 ExampleXXX
的形式。三种函数类似下面的签名形式:
// test 测试函数
func TestXXX(t *testing.T) { ... }
// benchmark 基准函数
func BenchmarkXXX(b *testing.B) { ... }
// examples 示例函数,其相关命名方式可以查看第一篇文章
func ExamplePrintln() {
Println("The output of\nthis example.")
// Output: The output of
// this example.
}
或
func ExamplePerm() {
for _, value := range Perm(4) {
fmt.Println(value)
}
// Unordered output: 4
// 2
// 1
// 3
// 0
}
Go 语言推荐测试文件和源代码文件放在一块,测试文件以 _test.go
结尾。比如,当前 package 有 calc.go
一个文件,我们想测试 calc.go
中的 Add
和 Mul
函数,那么应该新建 calc_test.go
作为测试文件。
example/
|--calc.go
|--calc_test.go
假如 calc.go
的代码如下:
package main
func Add(a int, b int) int {
return a + b
}
func Mul(a int, b int) int {
return a * b
}
那么 calc_test.go
中的测试用例可以这么写:
package main
import "testing"
func TestAdd(t *testing.T) {
if ans := Add(1, 2); ans != 3 {
t.Errorf("1 + 2 expected be 3, but %d got", ans)
}
if ans := Add(-10, -20); ans != -30 {
t.Errorf("-10 + -20 expected be -30, but %d got", ans)
}
}
- 测试用例名称一般命名为
Test
加上待测试的方法名。 - 测试用的参数有且只有一个,在这里是
t *testing.T
。
5 单元测试日志级别
每个测试用例可能并发执行,使用 testing.T 提供的日志输出可以保证日志跟随这个测试上下文一起打印输出。testing.T 提供了几种日志输出方法,详见下表所示。
方 法 | 备 注 |
---|---|
Log | 打印日志,同时结束测试 |
Logf | 格式化打印日志,同时结束测试 |
Error | 打印错误日志,同时结束测试 |
Errorf | 格式化打印错误日志,同时结束测试 |
Fatal | 打印致命日志,同时结束测试 |
Fatalf | 格式化打印致命日志,同时结束测试 |
6 单元测试
- 测试用例名称一般命名为
Test
加上待测试的方法名。 - 测试用的参数有且只有一个,在这里是
t *testing.T
。
7 基准测试
基准测试(benchmark)的参数是 *testing.B
,TestMain 的参数是 *testing.M
类型。
代码结构
example/
|--calc.go
|--calc_test.go
|--benchmark_test.go
7.1 代码运行和解释
import "testing"
func BenchmarkAdd(b *testing.B) {
var n int
for i := 0; i < b.N; i++ {
n++
}
}
func BenchmarkMul(b *testing.B) {
var n int
for i := 0; i < b.N; i++ {
n++
}
}
⋊> ~/g/s/b/testing go test -v -bench=. benchmark_test.go
goos: darwin
goarch: amd64
BenchmarkAdd
BenchmarkAdd-12 1000000000 0.263 ns/op
BenchmarkMul
BenchmarkMul-12 1000000000 0.255 ns/op
PASS
ok command-line-arguments 0.665s
-bench=.
表示运行 benchmark_test.go 文件里的所有基准测试,和单元测试中的-run
类似。- 第5行解释
- BenchmarkAdd-12 :显示基准测试名称
- 1000000000 :表示测试的次数,也就是 testing.B 结构中提供给程序使用的 N。
- “0.263 ns/op”表示每一个操作耗费多少时间(纳秒)。
-benchtime
参数可以自定义测试时间
1 秒 = 1000000000 纳秒
1秒(s) =1000毫秒(ms)
1毫秒(ms)=1000微秒 (us)
1微秒(us)=1000纳秒 (ns)
基准测试报告每一列值对应的含义如下:
type BenchmarkResult struct {
N int // 迭代次数
T time.Duration // 基准测试花费的时间
Bytes int64 // 一次迭代处理的字节数
MemAllocs uint64 // 总的分配内存的次数
MemBytes uint64 // 总的分配内存的字节数
}
如果基准测试需要在并行设置中测试性能,则可以使用 RunParallel
辅助函数 ; 这样的基准测试一般与 go test -cpu
标志一起使用:
通过 RunParallel
方法能够并行地执行给定的基准测试。RunParallel
会创建出多个 goroutine,并将 b.N 分配给这些 goroutine 执行,其中 goroutine 数量的默认值为 GOMAXPROCS。用户如果想要增加非 CPU 受限(non-CPU-bound)基准测试的并行性,那么可以在 RunParallel
之前调用 SetParallelism
(如 SetParallelism(2)
,则 goroutine 数量为 2*GOMAXPROCS)。RunParallel
通常会与 -cpu
标志一同使用。
func BenchmarkTemplateParallel(b *testing.B) {
templ := template.Must(template.New("test").Parse("Hello, {{.}}!"))
b.RunParallel(func(pb *testing.PB) {
// 每个 goroutine 有属于自己的 bytes.Buffer.
var buf bytes.Buffer
for pb.Next() {
// 循环体在所有 goroutine 中总共执行 b.N 次
buf.Reset()
templ.Execute(&buf, "World")
}
})
}
⋊> ~/g/s/b/testing go test -v -bench=BenchmarkTemplateParallel benchmark_test.go
goos: darwin
goarch: amd64
BenchmarkTemplateParallel
BenchmarkTemplateParallel-12 5213426 236 ns/op
PASS
ok command-line-arguments 2.687s
通过-benchtime
参数可以自定义测试时间
⋊> ~/g/s/b/testing go test -v -bench=. -benchtime=5s benchmark_test.go
goos: darwin
goarch: amd64
BenchmarkAdd
BenchmarkAdd-12 1000000000 0.257 ns/op
BenchmarkMul
BenchmarkMul-12 1000000000 0.258 ns/op
BenchmarkTemplateParallel
BenchmarkTemplateParallel-12 27029740 228 ns/op
PASS
ok command-line-arguments 8.157s
⋊> ~/g/s/b/testing go test -v -bench=. benchmark_test.go
goos: darwin
goarch: amd64
BenchmarkAdd
BenchmarkAdd-12 1000000000 0.246 ns/op
BenchmarkMul
BenchmarkMul-12 1000000000 0.255 ns/op
BenchmarkTemplateParallel
BenchmarkTemplateParallel-12 4983981 232 ns/op
BenchmarkFib1
BenchmarkFib1-12 731937631 1.66 ns/op
BenchmarkFib2
BenchmarkFib2-12 262092915 4.45 ns/op
BenchmarkFib3
BenchmarkFib3-12 157617190 7.47 ns/op
BenchmarkFib10
BenchmarkFib10-12 4234692 297 ns/op
BenchmarkFib20
BenchmarkFib20-12 34222 35516 ns/op
BenchmarkFib40
BenchmarkFib40-12 2 529998057 ns/op
PASS
ok command-line-arguments 12.166s
⋊> ~/g/s/b/testing go test -bench=. -run=none -benchmem 15:19:06
BenchmarkXXX
goos: darwin
goarch: amd64
pkg: basic_go/testing
BenchmarkXXX-12 BenchmarkXXX
BenchmarkXXX
BenchmarkXXX
BenchmarkXXX
BenchmarkXXX
1000000000 0.000023 ns/op 0 B/op 0 allocs/op
BenchmarkAdd-12 1000000000 0.260 ns/op 0 B/op 0 allocs/op
BenchmarkMul-12 1000000000 0.259 ns/op 0 B/op 0 allocs/op
BenchmarkTemplateParallel-12 5424362 236 ns/op 272 B/op 8 allocs/op
BenchmarkFib1-12 695810144 1.65 ns/op 0 B/op 0 allocs/op
BenchmarkFib2-12 262647230 4.62 ns/op 0 B/op 0 allocs/op
BenchmarkFib3-12 153866595 7.74 ns/op 0 B/op 0 allocs/op
BenchmarkFib10-12 4036820 315 ns/op 0 B/op 0 allocs/op
BenchmarkFib20-12 32605 36246 ns/op 0 B/op 0 allocs/op
BenchmarkFib40-12 2 543972525 ns/op 0 B/op 0 allocs/op
PASS
ok basic_go/testing 13.141s
7.2 分析基准测试数据
- cpu 使用分析:-cpuprofile=cpu.pprof
- 内存使用分析:-benchmem -memprofile=mem.pprof
- block分析:-blockprofile=block.pprof
在配合 pprof 就可以进行分析。
运行命令采样数据:
go test -bench=. -run=none -benchmem -memprofile=mem.pprof
go test -bench=. -run=none -blockprofile=block.pprof
go test -bench=. -run=none -benchmem -memprofile=mem.pprof -cpuprofile=cpu.pprof
7.3 基准测试原理
基准测试框架对一个测试用例的默认测试时间是 1 秒。开始测试时,当以 Benchmark 开头的基准测试用例函数返回时还不到 1 秒,那么 testing.B 中的 N 值将按 1、2、5、10、20、50……递增,同时以递增后的值重新调用基准测试用例函数。
8 参考
https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter09/09.0.html
http://c.biancheng.net/view/124.html
https://geektutu.com/post/quick-go-test.html#4-%E5%B8%AE%E5%8A%A9%E5%87%BD%E6%95%B0-helpers