前言
Go语言本身集成了轻量级的测试框架,由go test命令和testing包组成。包含单元测试和压力测试,是保证我们编写健壮Golang程序的有效工具。
演示环境
$ uname -a Darwin 18.6.0 Darwin Kernel Version 18.6.0: Thu Apr 25 23:16:27 PDT 2019; root:xnu-4903.261.4~2/RELEASE_X86_64 x86_64 $ go version go version go1.12.4 darwin/amd64
示例
老规矩,我会用一个简单的示例演示go test的用法,让大家有一个直观的感受。
$ ls my.go my_test.go $ go test -v === RUN TestAbs --- PASS: TestAbs (0.00s) PASS ok mytest 0.006s
my.go文件内容:
package mytest func Abs(a int) int { if a < 0 { return -1*a } return a }
my_test.go文件的内容:
package mytest import "testing" func TestAbs(t *testing.T) { result := Abs(-1) if result != 1 { t.Errorf("Abs(-1) = %d; want 1", result) } }
可以看出,测试文件是以_test.go结尾的文件,包含函数名TestXXX的文件签名func (t *testing.T)。测试框架会按函数定义的顺序依次执行Test开头的函数。如果测试函数调用错误函数,比如t.Error,t.Fail,那么测试就会认为是失败的。但是不会强制退出,测试程序还是会接着往下运行,除非调用t.Fatal,就会打印错误信息,并且强制退出。go test会自动编译运行_test.go结尾的文件,go build不会编译_test.go结尾的文件,所以不用担心test文件和正式文件定义为同一个包导致包大小增大。
详细用法
go test执行时会编译_test结尾的文件,执行文件中以Test,Benchmark,Example 开头的测试函数。建议_test.go文件和源文件声明为同一个包。单元测试函数TestXXX的参数是testing.T,BenchmarkXXX的参数是testing.B,函数内以b.N作为循环次数,其中N会动态变化。可以通过testing.T的Error,Errorf,Fail,Fatal,Fatalf 来说明测试不通过。
表格驱动测试
上述的示例单元测试用了-1这个测试用例来演示测试用法,但是在实际生产中我们编写一个测试函数肯定会有多种测试用例,各种边界条件,那这种情况应该怎么办呢?难道要每个测试用例拷贝一份上述的测试函数吗,显然是不合适的。这就介绍接下来的表格驱动测试(table driven test):
package mytest import "testing" func TestAbs(t *testing.T) { var testcases = []struct { in int out int }{ {-1, 1}, {0, 0}, {2, 2}, {123, 123}, {-30, -30}, } for _, tc := range testcases { result := Abs(tc.in) if result != tc.out { t.Fatalf("Abs(%d) = %d; want %d", tc.in, result, tc.out) } } }
表格的每一项是一个完整的测试用例,包含输入信息和期望的输出结果,有时候还包含测试用例名称等额外信息。这样我们就可以在表格里面编写各种测试用例场景,包括常规场景,边界场景,和一些异常场景。运行结果为:
$ go test -v === RUN TestAbs --- FAIL: TestAbs (0.00s) my_test.go:19: Abs(-30) = 30; want -30 FAIL exit status 1 FAIL mytest 0.005s
性能测试
性能测试函数以是Benchmark开头,格式为:
func Benchmark(b *testing.B)
go test 默认是不会运行_test.go文件中的Benchmark函数,需要通过-bench选项开启。演示代码:
package mytest import "testing" func BenchmarkAbs(b *testing.B) { for i := 0; i < b.N; i++ { result := Abs(i) if result != i { b.Errorf("benchmark faild, abs(%d) result %d, except %d", i, result, i) } } }
运行结果:
$ go test -bench=".*" goos: darwin goarch: amd64 pkg: mytest BenchmarkAbs-12 2000000000 0.26 ns/op PASS ok mytest 0.553s
-bench后面跟的是正则表达式,我们可以指定需要匹配运行的benchmark函数,示例中的.*表示运行所有的benchmark函数。
上述结果显示总共运行了0.553s,一共运行了2000000000次,平均每次运行的时间是0.26纳秒。
总结
文章介绍了Go语言自带的go test测试框架的单元测试和性能测试方法。下篇将会讲解gomock模拟实际的生产接口。
参考
https://golang.org/pkg/testing/
https://github.com/golang/go/wiki/TableDrivenTests
https://golang.org/doc/code.html#Testing