Go 测试风格指南

栏目: 编程工具 · 发布时间: 6年前

内容简介: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 测试风格指南》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

现代编译原理

现代编译原理

(美)安佩尔 / 赵克佳、黄春、沈志宇 / 人民邮电出版社 / 2006-4 / 45.00元

《现代编译原理:C语言描述》全面讲述了现代编译器的结构、编译算法和实现方法,是Andrew w.Apple的“虎书”——Modern Compiler Implementation——“红、蓝、绿”三序列之一。这三本书的内容基本相同。但是使用不同的语言来实现书中给出的一个编译器。本书使用的是更适合广大读者的c语言,而另外两本书分别采用ML语言和Java语言。本书的另一个特点是增加了一些其他编译原理......一起来看看 《现代编译原理》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具