go 语言 test 测试工具的标记 flag
cpu 标记
用来设置运行时,P的最大数量,即GOMAXPROCS
的值。可以设置一组值,在运行测试时,P被设置为不同的值分别运行测试函数。
最大P数量代表着 go 运行时系统同时运行goroutine的能力,可以被视为最大逻辑CPU的数量,在默认情况下,最大 P 数量就等于当前计算机 CPU 核心的实际数量,最大P可以大于或小于实际CPU的核心数量。
通过设置-cpu
的值,就可以来模拟程序在不同CPU数量下的表现。设置-cpu=2,4,8
go test -cpu=2,4,8 -bench=. gott/hello
goos: darwin
goarch: amd64
pkg: gott/hello
BenchmarkHello-2 5081475 228.6 ns/op
BenchmarkHello-4 5190867 215.8 ns/op
BenchmarkHello-8 5256798 212.6 ns/op
PASS
ok gott/hello 4.129s
性能测试函数BenchmarkHello
被执行了3次,最大P数量分别为2,4,8
如果没有指定-cpu
参数,测试运行时使用默认的最大P的数量,这个数量就等于当前CPU实际的核心数(比如你的CPU是4核,那么这个数量就是4)
go test -bench=. gott/hello
goos: darwin
goarch: amd64
pkg: gott/hello
BenchmarkHello-4 4670545 234.7 ns/op
PASS
ok gott/hello 1.381s
BenchmarkHello-4
表明默认P的值为4,即cpu是4核
count 标记
设置重复执行测试函数的次数
性能函数总的执行次数=-cpu
标记的值中正整数的个数 x -count
标记的值 x 探索式执行中测试函数的实际执行次数=2 * 2 * 5 =20
go test -count=2 -bench=. -cpu=2,4 gott/hello
goos: darwin
goarch: amd64
pkg: gott/hello
BenchmarkHello-2 5184015 224.1 ns/op
--- BENCH: BenchmarkHello-2
hello_test.go:30: NNNNN: 1
hello_test.go:30: NNNNN: 100
hello_test.go:30: NNNNN: 10000
hello_test.go:30: NNNNN: 1000000
hello_test.go:30: NNNNN: 5184015
BenchmarkHello-2 5676196 214.5 ns/op
--- BENCH: BenchmarkHello-2
hello_test.go:30: NNNNN: 1
hello_test.go:30: NNNNN: 100
hello_test.go:30: NNNNN: 10000
hello_test.go:30: NNNNN: 1000000
hello_test.go:30: NNNNN: 4618954
hello_test.go:30: NNNNN: 5676196
BenchmarkHello-4 5304111 213.8 ns/op
--- BENCH: BenchmarkHello-4
hello_test.go:30: NNNNN: 1
hello_test.go:30: NNNNN: 100
hello_test.go:30: NNNNN: 10000
hello_test.go:30: NNNNN: 1000000
hello_test.go:30: NNNNN: 5304111
BenchmarkHello-4 5286376 212.4 ns/op
--- BENCH: BenchmarkHello-4
hello_test.go:30: NNNNN: 1
hello_test.go:30: NNNNN: 100
hello_test.go:30: NNNNN: 10000
hello_test.go:30: NNNNN: 1000000
hello_test.go:30: NNNNN: 5286376
PASS
ok gott/hello 6.601s
功能函数总的执行次数=-cpu
标记的值中正整数的个数 x -count
标记的值=3 x 2 = 6
go test -v -count=2 -cpu=2,4,8 gott/hello
=== RUN TestHello
hello_test.go:17: number of runtime.GOMAXPROCS: 2
=== RUN TestHello
hello_test.go:17: number of runtime.GOMAXPROCS: 2
=== RUN TestHello
hello_test.go:17: number of runtime.GOMAXPROCS: 4
=== RUN TestHello
hello_test.go:17: number of runtime.GOMAXPROCS: 4
=== RUN TestHello
hello_test.go:17: number of runtime.GOMAXPROCS: 8
=== RUN TestHello
hello_test.go:17: number of runtime.GOMAXPROCS: 8
ok gott/hello 0.009s
对于功能测试,并不需要重复的执行多次,只需要执行一次即可,所以可以把-cpu
的数值设置为1,-count
的值不用设置,使用默认值为1就可以。功能测试关注的重点是验证逻辑是否正确,而不是程序的性能
go test -v -cpu=1 gott/hello
=== RUN TestHello
hello_test.go:17: number of runtime.GOMAXPROCS: 1
--- PASS: TestHello (0.00s)
PASS
ok gott/hello 0.008s
Parallel 标记
-parallel
标记可以指定同时运行测试用例的最大并发执行数,但仅适用于单个二进制测试文件,通过修改GOMAXPROCS
的值实现,该标记的默认值是测试运行时的最大 P 数量。
可以通过在测试函数中添加t.Parallel()
调用,以同时运行多个功能测试。默认情况下 go test 在运行测试时,为了加快测试速度,package 是被并行运行的,但每个包中的功能测试用例是被串行执行的。
func TestParallelPrintHello(t *testing.T) {
t.Parallel()
for i := 0; i < 5; i++ {
time.Sleep(200 * time.Millisecond)
t.Log("==========Hello==========")
}
}
func TestParallelPrintWorld(t *testing.T) {
t.Parallel()
t.Log("number of runtime.GOMAXPROCS:", runtime.GOMAXPROCS(0))
for i := 0; i < 5; i++ {
time.Sleep(200 * time.Millisecond)
t.Log("==========World==========")
}
}
使用t.Parallel()
指定需要并行执行的测试,在测试结果中可以看到TestParallelPrintWorld与TestParallelPrintHello交替输出,说明这两个测试函数是并行执行的
go test -v -parallel=8 gott/hello
=== RUN TestParallelPrintHello
=== PAUSE TestParallelPrintHello
=== RUN TestParallelPrintWorld
=== PAUSE TestParallelPrintWorld
=== CONT TestParallelPrintHello
=== CONT TestParallelPrintWorld
hello_test.go:43: number of runtime.GOMAXPROCS: 4
=== CONT TestParallelPrintHello
hello_test.go:36: ==========Hello==========
=== CONT TestParallelPrintWorld
hello_test.go:46: ==========World==========
hello_test.go:46: ==========World==========
=== CONT TestParallelPrintHello
hello_test.go:36: ==========Hello==========
hello_test.go:36: ==========Hello==========
=== CONT TestParallelPrintWorld
hello_test.go:46: ==========World==========
hello_test.go:46: ==========World==========
=== CONT TestParallelPrintHello
hello_test.go:36: ==========Hello==========
=== CONT TestParallelPrintWorld
hello_test.go:46: ==========World==========
=== CONT TestParallelPrintHello
hello_test.go:36: ==========Hello==========
--- PASS: TestParallelPrintWorld (1.02s)
--- PASS: TestParallelPrintHello (1.02s)
PASS
ok gott/hello 1.026s
- 测试结果中
runtime.GOMAXPROCS: 4
的值为4,并不是指定的8
,说明-parallel
标记并没有生成,因为测试运行的不是二进制文件,此时,即使不指定-parallel
也是可以的,如果想让更多的测试用例同时运行,可以在运行go test
时,指定-p
参数,运行更多的P,来同时执行更多的测试用例,比如设置p的值为4,让同时并行执行的最大并发数为4 - 使用
t.Parallel()
后,输出的信息多了PAUSE
和CONT
字段
如果加入-count=2
标记,对于测试用例来说,此时的并发不会是2个count之间的并发,这两个count也是串行执行的
go test -v -count=2 gott/hello
# 这里是第一遍count
=== RUN TestParallelPrintHello
=== PAUSE TestParallelPrintHello
=== RUN TestParallelPrintWorld
=== PAUSE TestParallelPrintWorld
=== CONT TestParallelPrintHello
=== CONT TestParallelPrintWorld
hello_test.go:43: number of runtime.GOMAXPROCS: 4
=== CONT TestParallelPrintHello
hello_test.go:36: ==========Hello==========
=== CONT TestParallelPrintWorld
hello_test.go:46: ==========World==========
=== CONT TestParallelPrintHello
hello_test.go:36: ==========Hello==========
=== CONT TestParallelPrintWorld
hello_test.go:46: ==========World==========
=== CONT TestParallelPrintHello
hello_test.go:36: ==========Hello==========
=== CONT TestParallelPrintWorld
hello_test.go:46: ==========World==========
=== CONT TestParallelPrintHello
hello_test.go:36: ==========Hello==========
=== CONT TestParallelPrintWorld
hello_test.go:46: ==========World==========
hello_test.go:46: ==========World==========
--- PASS: TestParallelPrintWorld (1.02s)
=== CONT TestParallelPrintHello
hello_test.go:36: ==========Hello==========
--- PASS: TestParallelPrintHello (1.02s)
# 这里是第二遍count
=== RUN TestParallelPrintHello
=== PAUSE TestParallelPrintHello
=== RUN TestParallelPrintWorld
=== PAUSE TestParallelPrintWorld
=== CONT TestParallelPrintHello
=== CONT TestParallelPrintWorld
hello_test.go:43: number of runtime.GOMAXPROCS: 4
hello_test.go:46: ==========World==========
=== CONT TestParallelPrintHello
hello_test.go:36: ==========Hello==========
hello_test.go:36: ==========Hello==========
=== CONT TestParallelPrintWorld
hello_test.go:46: ==========World==========
hello_test.go:46: ==========World==========
=== CONT TestParallelPrintHello
hello_test.go:36: ==========Hello==========
hello_test.go:36: ==========Hello==========
=== CONT TestParallelPrintWorld
hello_test.go:46: ==========World==========
hello_test.go:46: ==========World==========
=== CONT TestParallelPrintHello
hello_test.go:36: ==========Hello==========
--- PASS: TestParallelPrintWorld (1.01s)
--- PASS: TestParallelPrintHello (1.01s)
PASS
ok gott/hello 2.036s
源码文件
// hello.go
func main() {
hello("max")
}
func hello(name string) string {
return fmt.Sprint("hello ", name)
}
// hello_test.go
func TestHello(t *testing.T) {
name := "Max"
expected := fmt.Sprintf("hello %s", name)
greeting := hello(name)
if greeting != expected {
t.Errorf("hello(%s) = %s, expected = %s", name, greeting, expected)
}
t.Log(expected)
t.Log("number of runtime.GOMAXPROCS:", runtime.GOMAXPROCS(0))
}
func TestPrint(t *testing.T) {
t.Log("just Print")
}
func BenchmarkHello(b *testing.B) {
for i := 0; i < b.N; i++ {
hello("Max")
}
b.Log("NNNNN:", b.N)
}
func TestParallelPrintHello(t *testing.T) {
t.Parallel()
for i := 0; i < 5; i++ {
time.Sleep(200 * time.Millisecond)
t.Log("==========Hello==========")
}
}
func TestParallelPrintWorld(t *testing.T) {
t.Parallel()
t.Log("number of runtime.GOMAXPROCS:", runtime.GOMAXPROCS(0))
for i := 0; i < 5; i++ {
time.Sleep(200 * time.Millisecond)
t.Log("==========World==========")
}
}
小结
- 可以通过运行
runtime.GOMAXPROCS(0)
获得运行时的最大P的数量 - 在功能测试中,无法避免依赖一些外部环境,比如数据库的连接,第三方接口的调用,应该对这些外部环境进行仿造(mock),从而得到一个纯净的测试环境
go help testflag
查看 flag 帮助文件