



Go测试代码的逻辑十分简单,约束也甚少,但我们发现:上面仅有三组预置输入数据的示例的测试代码已显得十分冗长,如果为测试预置的数据组数增多,测试函数本身就将变得十分庞大。并且,我们看到上述示例的测试逻辑中存在很多重复的代码,显得十分烦琐。我们来尝试对上述示例做一些改进:
// chapter8/sources/table_driven_strings_test.go
func TestCompare(t *testing.T) {
compareTests := []struct {
a, b string
i int
}{
{"", "", 0},
{"a", "", 1},
{"", "a", -1},
}
for _, tt := range compareTests {
cmp := strings.Compare(tt.a, tt.b)
if cmp != tt.i {
t.Errorf(`want %v, but Compare(%q, %q) = %v`, tt.i, tt.a, tt.b, cmp)
}
}
}
在上面这个改进的示例中,我们将之前示例中重复的测试逻辑合并为一个,并将预置的输入数据放入一个自定义结构体类型的切片中。这个示例的长度看似并没有比之前的实例缩减多少,但它却是 一个可扩展的测试设计 。如果增加输入测试数据的组数,就像下面这样:
// chapter8/sources/table_driven_strings_more_cases_test.go
func TestCompare(t *testing.T) {
compareTests := []struct {
a, b string
i int
}{
{"", "", 0},
{"a", "", 1},
{"", "a", -1},
{"abc", "abc", 0},
{"ab", "abc", -1},
{"abc", "ab", 1},
{"x", "ab", 1},
{"ab", "x", -1},
{"x", "a", 1},
{"b", "x", -1},
{"abcdefgh", "abcdefgh", 0},
{"abcdefghi", "abcdefghi", 0},
{"abcdefghi", "abcdefghj", -1},
}
for _, tt := range compareTests {
cmp := strings.Compare(tt.a, tt.b)
if cmp != tt.i {
t.Errorf(`want %v, but Compare(%q, %q) = %v`, tt.i, tt.a, tt.b, cmp)
}
}
}
可以看到,无须改动后面的测试逻辑, 只需在切片中增加数据条目即可 。在这种测试设计中,这个自定义结构体类型的切片(上述示例中的compareTests)就是一个 表 (自定义结构体类型的字段就是列),而基于这个数据表的测试设计和实现则被称为 “表驱动的测试” 。