

新闻资讯
技术学院表格驱动测试是Go中通过结构体切片组织测试用例并遍历执行的模式。核心为定义含name、input、want等字段的结构体切片,用t.Run运行子测试,确保用例独立、可读、可维护。
Go 语言中没有内置的「数据驱动」或「参数化测试」语法,但用切片 + 结构体组合就能自然实现表格驱动测试。它的核心是把测试用例组织成 []struct{input, want, name string} 这样的切片,再用 for range 遍历执行——不是靠框架,而是靠 Go 的简洁语法和测试习惯。
以测试一个字符串首字母大写的函数为例,关键点在于:结构体字段命名清晰、t.Run() 使用子测试名、每个用例独立断言。
func TestCapitalize(t *testing.T) {
tests := []struct {
name string
input string
want string
}{
{"empty string", "", ""},
{"single lowercase", "hello", "Hello"},
{"already capitalized", "World", "World"},
{"mixed case", "gOlang", "Golang"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Capitalize(tt.input); got != tt.want {
t.Errorf("Capitalize(%q) = %q, want %q", tt.input, got, tt.want)
}
})
}
}
t.Run() 让每个用例在 go test -v 中显示独立名称,失败时能准确定位name → input → want 排列,符合阅读直觉tt),否则并发子测试可能捕获错误引用(Go 1.21+ 默认启用 -race 检测)当被测函数返回 (string, error) 时,表格结构需增加 errWant 字段,并用 errors.Is() 或 assert.Equal(t, err.Error(), ...) 判断错误内容——直接比较 err == nil 不够,因为错误值不支持指针等价判断。
func TestParseID(t *testing.T) {
tests := []struct {
na
me string
input string
want int
errWant error
}{
{"valid number", "123", 123, nil},
{"empty", "", 0, errors.New("empty ID")},
{"non-digit", "abc", 0, errors.New("invalid digit")},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseID(tt.input)
if !errors.Is(err, tt.errWant) {
t.Errorf("ParseID(%q) error = %v, want %v", tt.input, err, tt.errWant)
return
}
if got != tt.want {
t.Errorf("ParseID(%q) = %d, want %d", tt.input, got, tt.want)
}
})
}
}
errors.Is() 而非 == 比较 error,尤其当错误由 fmt.Errorf("...") 构造时errWant 是动态构造的(比如含时间戳),改用 strings.Contains(err.Error(), "...")
return 后忽略后续断言;上面示例中先检查 error 再检查结果,是常见且安全的顺序真正影响可维护性的不是写法,而是组织方式和边界意识:
tests := []struct{...} 里,避免拆到全局变量或外部文件——否则无法一眼看清输入输出关系input 或 want,例如 input: generateRandomString(5),这会让测试不可重现TestParseID_InvalidInput、TestParseID_ValidInput),而不是堆在一个大表格里