上QQ阅读APP看书,第一时间看更新
42.2 表驱动的测试实践
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)就是一个表(自定义结构体类型的字段就是列),而基于这个数据表的测试设计和实现则被称为“表驱动的测试”。