编写 golang 测试代码

单元测试

测试文件以 _test.go 结尾。
包名与被测试包名相同或者为 测试包名_test
测试方法为 TestXxx 的形式,传入固定参数 *testing.T,如下:

func TestAdd(t *testing.T) {
    data := []struct {
        a   int
        b   int
        res int
    }{
        {1, 1, 2},
        {2, 2, 4},
        {3, 3, 4},
        {4, 4, 8},
    }
    for i, v := range data {
        res := Add(v.a, v.b)
        if res == v.res {
            t.Logf("index: %d, ok\n", i)
        } else {
            t.Logf("index: %d, get %d, want: %d\n", i, res, v.res)
        }
    }
}

/*
输出
LailydeMBP ➜ go test -v -run=TestAdd
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
        t_test.go:19: index: 0, ok
        t_test.go:19: index: 1, ok
        t_test.go:21: index: 2, get 6, want: 4
        t_test.go:19: index: 3, ok
PASS
ok      test/test1      0.006s
*/

执行测试用例的时候在测试文件目录执行 go test -v -run=xxx
-run 参数指定测试的方法名,支持正则表达式。如果不使用则执行所有测试方法。
-v 参数表示打印程序中的输出

测试包里的 init() 方法会在测试方法之前执行,所以可以用来准备 db,cache 等数据。
测试包里的 init() 方法只会在 go test 的情况下会执行。

testing.T
testing.T 变量用来输出错误。它的 Log() 方法用来正常输出数据,Error() 方法输出错误并标记测试失败。Fatal() 方法表示测试失败后跳出该测试函数。

基准测试

基准测试的模版如下

var (
    data = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
)

func BenchmarkFor(b *testing.B) {
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        For(data)
    }
}

func BenchmarkRange(b *testing.B) {
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        Range(data)
    }
}

/*
LailydeMBP ➜ go test -bench=.
goos: darwin
goarch: amd64
pkg: test/test1
BenchmarkFor-4           2000000               850 ns/op
BenchmarkRange-4         2000000               837 ns/op
PASS
ok      test/test1      5.122s

*/

文件名,报名和之前一样。方法名为 BenchmarkXxxx(b *testing.B){} 的形式。ResetTimer() 方法用来重置计时器。
执行测试用例使用 go test -bench=.
-bench 指定执行的方法。
-run 因为默认 go test 会执行所有的单元测试,可以将 -run 指定到一个不存在的单元测试,这样就可以只输出基准测试的结果。

输出里方法名后的 -8 表示运行时对应的 GOMAXPROCS 的值。 2000000 表示 for 循环的次数。后面的 850ns/op 表示平均每次执行花费 850 纳秒。