如何为带~string约束的Go泛型方法编写表驱动测试?
解决Go泛型函数的表驱动测试问题
针对你遇到的泛型函数L的表驱动测试问题,核心原因是Go的切片是同构的,所有元素必须是同一具体类型——自定义类型T和原生string属于不同类型,没法直接放在同一个普通匿名结构体切片里。下面提供几种实用的解决方案:
方案1:使用interface{}存储输入,配合类型断言
通过interface{}兼容不同类型的输入,在测试逻辑中用类型断言分发到泛型函数:
import "testing" import "fmt" func L[T ~string](s T) string { return string(s) } func TestL(t *testing.T) { type T string tests := []struct { in interface{} want string }{ {in: T("foo"), want: "foo"}, {in: "foo", want: "foo"}, {in: T("bar"), want: "bar"}, {in: "bar", want: "bar"}, } for _, tc := range tests { t.Run(fmt.Sprintf("input=%v(type=%T)", tc.in, tc.in), func(t *testing.T) { var got string // 根据输入类型调用泛型函数 switch s := tc.in.(type) { case string: got = L(s) case T: got = L(s) default: t.Fatalf("不支持的输入类型:%T", s) } if got != tc.want { t.Errorf("结果不符:got=%q, want=%q", got, tc.want) } }) } }
方案2:封装泛型测试函数,批量执行用例
把测试逻辑封装成泛型函数,然后遍历不同类型的测试用例调用它,兼顾类型安全和代码简洁:
import "testing" import "fmt" func L[T ~string](s T) string { return string(s) } // 泛型测试逻辑,针对单一类型的输入 func testL[T ~string](t *testing.T, input T, want string) { t.Run(fmt.Sprintf("%T(%q)", input, input), func(t *testing.T) { got := L(input) if got != want { t.Errorf("结果不符:got=%q, want=%q", got, want) } }) } func TestL(t *testing.T) { type T string // 定义所有测试用例,用interface{}存储不同类型的输入 testCases := []struct { input interface{} want string }{ {T("foo"), "foo"}, {"foo", "foo"}, {T("baz"), "baz"}, {"baz", "baz"}, } for _, tc := range testCases { // 分发到对应的泛型测试函数 switch s := tc.input.(type) { case string: testL(t, s, tc.want) case T: testL(t, s, tc.want) default: t.Fatalf("不支持的输入类型:%T", s) } } }
为什么直接用匿名结构体无法实现?
Go的泛型约束~string只是对类型的限制,不是具体类型。自定义T和原生string是两个不同的具体类型,而普通切片要求所有元素的类型完全一致,因此无法在同一个非泛型切片中同时存放这两种类型的实例。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

