子测试和子基准测试的使用

发表于:2017-7-19 10:33

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:polaris    来源:博客

  介绍
  Go 1.7,testing 包在 T 和 B 类型上引入了一个 Run 方法,允许创建子测试和子基准测试。子测试和子基准测试的引入可以更好地处理故障(failures),细化控制从命令行运行的测试,并行控制,并且经常会使代码更简单、更易于维护。
  Table-driven 测试
  在详细介绍之前,首先讨论在 Go 中编写测试的常用方法。 一系列相关验证可以通过循环遍历一系列测试用例来实现:
  func TestTime(t *testing.T) {
      testCases := []struct {
          gmt  string
          loc  string
          want string
      }{
          {"12:31", "Europe/Zuri", "13:31"},     // incorrect location name
          {"12:31", "America/New_York", "7:31"}, // should be 07:31
          {"08:08", "Australia/Sydney", "18:08"},
      }
      for _, tc := range testCases {
          loc, err := time.LoadLocation(tc.loc)
          if err != nil {
              t.Fatalf("could not load location %q", tc.loc)
          }
          gmt, _ := time.Parse("15:04", tc.gmt)
          if got := gmt.In(loc).Format("15:04"); got != tc.want {
              t.Errorf("In(%s, %s) = %s; want %s", tc.gmt, tc.loc, got, tc.want)
          }
      }
  }
  通常称为 table-driven(表格驱动) 测试,相比每次测试重复相同代码,减少了重复代码的数量,并且可以直接添加更多的测试用例。
  Table-driven 基准测试
  在 Go 1.7 之前,不可能使用相同的 table-driven 方法进行基准测试。 基准测试对整个函数的性能进行测试,因此迭代基准测试只是将它们整体作为一个基准测试。
  常见的解决方法是定义单独的顶级基准,每个基准用不同的参数调用共同的函数。 例如,在 1.7 之前,strconv 包的 AppendFloat 的基准测试看起来像这样:
  func benchmarkAppendFloat(b *testing.B, f float64, fmt byte, prec, bitSize int) {
      dst := make([]byte, 30)
      b.ResetTimer() // Overkill here, but for illustrative purposes.
      for i := 0; i < b.N; i++ {
          AppendFloat(dst[:0], f, fmt, prec, bitSize)
      }
  }
   
  func BenchmarkAppendFloatDecimal(b *testing.B) { benchmarkAppendFloat(b, 33909, 'g', -1, 64) }
  func BenchmarkAppendFloat(b *testing.B)        { benchmarkAppendFloat(b, 339.7784, 'g', -1, 64) }
  func BenchmarkAppendFloatExp(b *testing.B)     { benchmarkAppendFloat(b, -5.09e75, 'g', -1, 64) }
  func BenchmarkAppendFloatNegExp(b *testing.B)  { benchmarkAppendFloat(b, -5.11e-95, 'g', -1, 64) }
  func BenchmarkAppendFloatBig(b *testing.B)     { benchmarkAppendFloat(b, 123456789123456789123456789, 'g', -1, 64) }
  ...
  使用 Go 1.7 中提供的 Run 方法,现在将同一组基准表示为单个顶级基准:
  func BenchmarkAppendFloat(b *testing.B) {
      benchmarks := []struct{
          name    string
          float   float64
          fmt     byte
          prec    int
          bitSize int
      }{
          {"Decimal", 33909, 'g', -1, 64},
          {"Float", 339.7784, 'g', -1, 64},
          {"Exp", -5.09e75, 'g', -1, 64},
          {"NegExp", -5.11e-95, 'g', -1, 64},
          {"Big", 123456789123456789123456789, 'g', -1, 64},
          ...
      }
      dst := make([]byte, 30)
      for _, bm := range benchmarks {
          b.Run(bm.name, func(b *testing.B) {
              for i := 0; i < b.N; i++ {
                  AppendFloat(dst[:0], bm.float, bm.fmt, bm.prec, bm.bitSize)
              }
          })
      }
  }
  每次调用 Run 方法创建一个单独的基准测试。调用 Run 方法的基准函数只运行一次,不进行性能度量。
  新代码行数更多,但是更可维护,更易读,并且与通常用于测试的 table-driven 方法一致。 此外,共同的 setup 代码现在在 Run 之间共享,而不需要重置定时器。
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号