testing - 子测试与子基准测试

从 Go 1.7 开始,引入了一个新特性:子测试(subtests)与子基准测试(sub-benchmarks),它意味着您现在可以拥有嵌套测试,这对于过滤执行特定测试用例非常有用。

T 和 B 的 Run 方法允许定义子单元测试和子基准测试,而不必为它们单独定义函数。这便于创建基于 Table-Driven 的基准测试和层级测试。它还提供了一种共享通用 setuptear-down 代码的方法:

  1. func TestFoo(t *testing.T) {
  2. // <setup code>
  3. t.Run("A=1", func(t *testing.T) { ... })
  4. t.Run("A=2", func(t *testing.T) { ... })
  5. t.Run("B=1", func(t *testing.T) { ... })
  6. // <tear-down code>
  7. }

每个子测试和子基准测试都有一个唯一的名称:由顶层测试的名称与传递给 Run 的名称组成,以斜杠分隔,并具有可选的尾随序列号,用于消除歧义。

命令行标志 -run-bench 的参数是非固定的正则表达式,用于匹配测试名称。对于由斜杠分隔的测试名称,例如子测试的名称,它名称本身即可作为参数,依次匹配由斜杠分隔的每部分名称。因为参数是非固定的,一个空的表达式匹配任何字符串,所以下述例子中的 “匹配” 意味着 “顶层/子测试名称包含有”:

  1. go test -run '' # 执行所有测试。
  2. go test -run Foo # 执行匹配 "Foo" 的顶层测试,例如 "TestFooBar"。
  3. go test -run Foo/A= # 对于匹配 "Foo" 的顶层测试,执行其匹配 "A=" 的子测试。
  4. go test -run /A=1 # 执行所有匹配 "A=1" 的子测试。

子测试也可用于程序并行控制。只有子测试全部执行完毕后,父测试才会完成。在下述例子中,所有子测试之间并行运行,此处的 “并行” 只限于这些子测试之间,并不影响定义在其他顶层测试中的子测试:

  1. func TestGroupedParallel(t *testing.T) {
  2. for _, tc := range tests {
  3. tc := tc // capture range variable
  4. t.Run(tc.Name, func(t *testing.T) {
  5. t.Parallel()
  6. ...
  7. })
  8. }
  9. }

在所有子测试并行运行完毕之前,Run 方法不会返回。下述例子提供了一种方法,用于在子测试并行运行完毕后清理资源:

  1. func TestTeardownParallel(t *testing.T) {
  2. // This Run will not return until the parallel tests finish.
  3. t.Run("group", func(t *testing.T) {
  4. t.Run("Test1", parallelTest1)
  5. t.Run("Test2", parallelTest2)
  6. t.Run("Test3", parallelTest3)
  7. })
  8. // <tear-down code>
  9. }

导航