内容简介:Go 测试的一个小风格(自认为)指南。关于写好测试的文章比我在这写的要多的多。但我写的主要是关于风格而不是技术。尝试在可行的情况下使用 table-driven 测试,但当不可行时,可以复制一些代码;不要强制使用它(例如,有时候除了一两个案例之外,更容易为这之外的情况编写一个 table-driven 的测试;实际情况就是如此)。始终为一个测试用例使用相同变量名会使它更容易为大量代码工作。你不必使用 tt,但是在 Go 标准库中它是最常用的( 564 次对比 tc 用了 116 次)。
Go 测试的一个小风格(自认为)指南。关于写好测试的文章比我在这写的要多的多。但我写的主要是关于风格而不是技术。
使用 table-drive 测试,并始终使用 tt 作为测试用例
尝试在可行的情况下使用 table-driven 测试,但当不可行时,可以复制一些代码;不要强制使用它(例如,有时候除了一两个案例之外,更容易为这之外的情况编写一个 table-driven 的测试;实际情况就是如此)。
始终为一个测试用例使用相同变量名会使它更容易为大量代码工作。你不必使用 tt,但是在 Go 标准库中它是最常用的( 564 次对比 tc 用了 116 次)。
可以看看 TableDrivenTests 。
例如:
tests := []struct { // ... }{} for _, tt := range tests { }
使用子测试
使用子测试可以从 table 中运行一个单独的测试,且可以容易的看出哪个测试完全失败了。由于子测试是比较新的版本( Go 1.7,2016年10月),所以许多现存的测试不能使用它们(子测试)。
如果测试内容很明显,我倾向于简单地使用测试编号;如果不明显或有很多测试用例,就添加一个测试名。
可以看下 使用子测试和子基准
例如:
tests := []struct { // ... }{} for i, tt := range tests { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { got := TestFunction(tt.input) if got != tt.want { t.Errorf("failed for %v ...", tt.input) } }) }
不要忽略错误
我经常看到在测试中有人忽略错误。这是不好的想法并且使失败的测试混乱。
例如:
got, err := Fun() if err != nil { t.Fatalf("unexpected error: %v", err) }
或者:
got, err := Fun() if err != tt.wantErr { t.Fatalf("wrong error\ngot: %v\nwant: %v", err, tt.wantErr) }
我经常使用 ErroContains
,它是一个很有用的帮助函数对测试错误信息(避免一些 if err != nil && [..]
)。
检查你的测试作为常规代码
测试代码也会失败,错误,所以需要维护。如果你认为运行 linter 对你的正规代码是值得的,那么对你的测试运行也是一样值得的。(例如:go vet, errcheck 等)。
使用 want 和 got
want 比 expected 短,got 比 actual 短。短命名总是有优势的,IMHO,并且特别有利于对齐输出(看下面的例子)。
例如:
cases := []struct { want string wantCode int }{}
添加有用的,可对齐的信息
当一个测试失败伴随着无用的错误信息,或者是一个混乱的错误信息,使你很难看出准确的错误时是很恼人的。
这不是特别有用:
t.Errorf("wrong output: %v", got)
当测试失败时,它告诉我们得到了错误输出,但是我们想要得到的是什么呢?
这个就比较好:
name := "test foo" got := "this string!" want := "this string" t.Errorf("wrong output for %v, want %v; got %v", name, got, want)
下面这个很难看到准确的失败:
--- FAIL: TestX (0.00s) a_test.go:9: wrong output for test foo, want this string!; got this string
当把它对齐,就很容易了:
name := "test foo" want := "this string" t.Run(name, func(t *testing.T) { got := "this string!" t.Errorf("wrong output\ngot: %q\nwant: %q", got, want) })
--- FAIL: TestX (0.00s) --- FAIL: TestX/test_foo (0.00s) a_test.go:10: wrong output got: "this string!" want: "this string"
注意 got:
后面的俩个空格,是为了和 want
对齐的。如果我使用 expected
就要使用6个空格。
我还倾向于使用 %q
或 %#v
,因为这会很清楚的显示后面的空白或不可打印字符。
使用 diff 比较较大的对象;例如用 go-cmp :
if d := cmp.Diff(got, tt.want); d != "" { t.Errorf("(-got +want)\n:%s", d) }
--- FAIL: TestParseFilter (0.00s) --- FAIL: TestParseFilter/alias (0.00s) query_test.go:717: (-got +want) :{jsonapi.Filter}.Alias: -: "fail" +: "alias"
搞清楚要测试什么
有时我看到一些测试,我困惑 “这是在测试什么?” 如果测试失败的原因不名这会令人特别困惑。应该改哪?测试正确吗?
例如:
cases := []struct { name string }{ { "space after @", }, { "unicode space before @", }, // ... }
如果添加 name
到存在的测试用例一定比注释要更有用。
反馈
你可以给我发邮件:martin@arp242.ent 或者 提交一个 GitHub 问题 反馈,提问等。
以上所述就是小编给大家介绍的《Go 测试风格指南》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JSON 在线解析
在线 JSON 格式化工具
HSV CMYK 转换工具
HSV CMYK互换工具