Skip to content

Latest commit

 

History

History
133 lines (83 loc) · 3.73 KB

ch11.md

File metadata and controls

133 lines (83 loc) · 3.73 KB

第十一章 测试

  • Go 的测试方法依赖于命令 go test 和一些能用 go test 运行的测试函数的编写约定。编写测试用例和编写常规的 Go 代码没有区别。

11.1 go test 工具

  • 在一个包目录中,以 _test.go 结尾的文件由 go test 命令编译

  • *_test.go 文件中有三种特殊函数:

    • 以 Test 前缀命名的函数:检测程序逻辑的正确性,go test 运行测试函数并提供报告

    • 以 Benchmar 开头的函数:测试操作的性能,go test 汇报操作的评价执行时间

    • 以 Example 开头的函数: 用来提供机器检查过的文档

11.2 Test 函数

  • 测试函数的签名必须如下。 testing.T 提供了汇报测试结果和日志记录功能,参考 go doc

    import testing
    
    func TestName(t *testing.T) {
      // ...
    }
  • 给 go test 加上 -run="正则表达式" 运行名称匹配的测试函数,或者运行某个测试函数

  • 可以把多个测试用例的输入和结果放到一个表里:

    func TestCase(t *testing.T) {
      var tests = []struct {
        input string
        want  bool
      }{
        {"", true},
        {"a",true},
      }
      for _, test := range tests {
        //...
      }
    }
  • 用t.Error输出错误,一般格式是 f(x)=y, want z

  • 使用 t.Fatal 或 t.Fatalf 函数来终止测试

11.2.1 随机测试

  • 编写一个辅助函数返回一个随机输出作为被测试函数的输入

  • 测试函数中反复调用辅助函数得到输入来测试

11.2.2 测试命令

  • 将 _test.go 文件声明为 main 包,测试函数调用被测试函数。

  • go test 命令不会执行 main() 函数

11.2.3 白盒测试

  • 白盒测试通过把测试函数放入被测函数的包内,共享包全局变量和函数

  • 在测试用例中,重新赋值全局变量和函数变量绕开真正的操作

  • 在测试用例开始时保存被修改的变量值,用defer在测试结束时还原被修改的变量

11.2.4 外部测试包

  • 为了避免循环引用,使用外部测试包来测试有循环依赖的两个包

  • 在包内的 export_test.go 测试文件中添加函数声明,将内部的功能暴露给外部测试。

11.2.5 编写有效测试

  • 在编写测试函数时应避免过早抽象

  • 一个好的测试应首先实现所期望的具体行为,并仅在这个时候再使用工具函数来使代码简洁并避免重复。

11.2.6 避免脆弱的测试

  • 仅检查关心的属性来避免写出脆弱的测试

  • 值得写出一个稳定的函数来从复杂的输出中提取核心内容,否则时间就会被花在修复奇怪失败的测试上

11.3 覆盖率

# 运行测试,计算覆盖率
go test -coverprofile=c.out -covermode=count

# 浏览器查看覆盖率结果
go tool cover -html=c.out

11.4 Benchmark 函数

  • 基准测试函数以 Benchmark 作为前缀,并接收一个 *testing.B 类型的参数。用 b.N 控制循环次数。在 for 循环外围执行测试的初始化工作。

    import "testing"
    
    func BenchmarkCase(b *testing.B){
      for i := 0; i < b.N; i++ {
        //..
      }
    }
  • go test -bench=. 执行基准测试。-benchmem 记录内存分配统计数据

  • 通常统计两个不同操作的相对耗时更有意义:

    func benchmark(b *testing.B, size int) { /*...*/}
    func Benckmark10(b *testing.B) { benchmark(b, 10) }
    func Benckmark100(b *testing.B) { benchmark(b, 100) }
    func Benckmark1000(b *testing.B) { benchmark(b, 1000) }

11.5 性能剖析

  • go test 加上参数 -cpuprofile, -blockprofile 或 -memprofile

  • go tool pprof 输出报告

11.6 Example 函数

  • 函数以 Example 作为前缀, 没有参数。可以作为文档示例;通过 go test 的执行;提供手动实验代码