golang testing 使用教程

单测是提高代码质量的重要一环,在提交代码尤其是开源社区单测一般是必需要随代码一起提交的,下面我们来看一下Golang中是如何写单元测试的。 Go中提供了专门用来写单元测试的包 testing, 运行时只需要 go test 即可。 单元测试主要分为以下三类:

  • 功能测试(Test)
  • 性能测试(Benchmark)
  • 示例测试(Example)

测试文件名称一般是源代码文件加上 "_test.go", 比如 源代码文件为 add.go ,则测试文件名称为add_test.go。

在展开单元测试之前先讲下,testing包中的输出函数:

  • t.Log() : 正常日志输出;
  • t.Errorf(): 错误日志输出,当前函数继续运行;
  • t.Fatalf(): 错误日志输出,当前函数立刻退出;

功能测试

测试函数有两点约定:

  1. 函数名必需以Test为前缀,如需要测试Add函数则名称应该为 TestAdd;
  2. 函数参数必需为 t * testing.T; 完整的功能测试如下所示:
 1// add.go
 2func Add(a int, b int) int {
 3    return a + b 
 4}
 5
 6// add_tesg.go
 7func TestAdd(t *testing.T){
 8    a := 1
 9    b := 2 
10    want := a + b 
11    got := Add(a, b)
12    if want != got {
13        t.Errorf("Add(%d, %d) = %d, want %d", a, b, got, want)
14    }
15}

在运行的时候可以使用 go test 执行该目录下的所有功能测试函数, 也可以通过 go test -run Xxxx 指定特定测试函数运行,-v 可以显示每个测试函数的执行结果, 如下所示:

1➜    go test -v
2=== RUN   TestAdd
3--- PASS: TestAdd (0.00s)
4PASS
5ok  	learn/golang/test	0.185s

性能测试

性能测试函数有两点约定:

  1. 函数名必需以Benchmark为前缀,如需要测试Add函数则名称应该为 BenchmarkAdd;
  2. 函数参数必需为 b * testing.B; 完成测试函数如下所示:
1func BenchmarkRandInt(b *testing.B) {
2	for i := 0; i < b.N; i++ {
3		rand.Int()
4	}
5}

在运行的时候可以执行如下命令:

  1. go test -bench=. :执行该目录下的所有测试函数(包含功能测试和性能测试);
  2. go test -bench=. -run=^$ :执行该目录下的性能测试函数;
  3. go test -bench=BenchmarkRandInt -run=^$: 执行性能测试函数BenchmarkRandInt;

-bench: 只有有个该标志才会执行性能测试函数; -run: 这个标志表示要执行哪些功能测试函数,默认是全部,^$ 表示空,即不执行功能测试函数;

执行结果如下:

1➜    go test -bench=BenchmarkRandInt -run=^$
2goos: darwin
3goarch: amd64
4pkg: learn/golang/test
5BenchmarkRandInt-8   	70695550	        16.9 ns/op
6PASS
7ok  	learn/golang/test	1.956s

对于测试结果的输出,重点字段解释如下: BenchmarkRandInt-8 : 说明执行的测试函数是BenchmarkRandInt, 8说明使用的最大P是8个;
70695550: 执行的总次数;
16.9 ns/op : 单次平均耗时;
另外如果执行测试函数前有一些耗时的操作,可以使用b.ResetTimer() 重置以下定时器;

示例测试

示例测试函数提供了运行并验证的功能,既可以当作文档又可以用来测试; 示例测试有如下约定:

  1. 函数名必需以Example为前缀;
  2. 通过注释 Output: 来说明正确的输出结果,,在运行测试时,go 会将示例函数的输出和 "Output:" 注释中的值做比较;
  3. 如果输出的顺序不固定可以使用 "Unordered output:" 开头的注释; 完整测试如下所示:
 1func ExamplePerm() {
 2    for _, value := range Perm(5) {
 3        fmt.Println(value)
 4    }
 5    // Unordered output: 4
 6    // 2
 7    // 1
 8    // 3
 9    // 0
10}

参考

golang testing

Posts in this Series