使用go-sqlmock测试时gosnowflake.Array类型断言失败的解决问询
解决gosnowflake.Array与go-sqlmock值转换器的类型断言问题
问题核心
gosnowflake.Array返回的是自定义切片指针类型(比如*stringArray,其中stringArray是[]string的类型别名),Go中类型别名与原类型属于不同的静态类型,因此直接断言v.(*[]T)会失败。
解决方案
方法1:通过反射提取底层切片(推荐,无内部依赖)
利用反射判断值的底层类型,只要是指向元素类型为T的切片指针,就可以提取内容进行验证,完全不依赖gosnowflake的内部实现:
import "reflect" func (opt arrayConverterOption[T]) ConvertValue(v any) (driver.Value, error) { rv := reflect.ValueOf(v) // 校验是否为指向切片的指针 if rv.Kind() == reflect.Ptr && rv.Elem().Kind() == reflect.Slice { elemType := rv.Elem().Type().Elem() targetType := reflect.TypeOf(*new(T)) // 校验切片元素类型与T匹配 if elemType == targetType { slice := rv.Elem().Interface().([]T) // 执行你的验证逻辑 Expect(slice).Should(HaveLen(len(opt.Expected))) for i, c := range slice { Expect(c).Should(Equal(opt.Expected[i])) } return "TEST_RESULT", nil } } // 非目标类型直接返回 fmt.Printf("Type: %T\n", v) return v, nil }
方法2:针对gosnowflake内部类型断言(不推荐,依赖内部实现)
如果允许依赖gosnowflake的未导出内部类型(注意:内部类型可能随版本变更),可以直接针对具体类型断言:
// 注意:仅当gosnowflake.stringArray是导出类型时可用,否则编译报错 func (opt arrayConverterOption[T]) ConvertValue(v any) (driver.Value, error) { // 针对string类型的特殊处理 if strArr, ok := v.(*gosnowflake.stringArray); ok { slice := []string(*strArr) Expect(slice).Should(HaveLen(len(opt.Expected))) for i, c := range slice { Expect(c).Should(Equal(opt.Expected[i])) } return "TEST_RESULT", nil } // 原通用切片断言逻辑 casted, ok := v.(*[]T) if ok { Expect(*casted).Should(HaveLen(len(opt.Expected))) for i, c := range *casted { Expect(c).Should(Equal(opt.Expected[i])) } return "TEST_RESULT", nil } fmt.Printf("Type: %T\n", v) return v, nil }
方法3:利用gosnowflake公开API(优先检查)
查看gosnowflake的Array类型是否提供了公开方法获取底层切片(比如Values()、Slice()等),如果有可以直接调用:
// 假设Array类型有公开的GetSlice方法返回对应类型切片 func (opt arrayConverterOption[T]) ConvertValue(v any) (driver.Value, error) { if arr, ok := v.(interface{ GetSlice() []T }); ok { slice := arr.GetSlice() // 验证逻辑 Expect(slice).Should(HaveLen(len(opt.Expected))) for i, c := range slice { Expect(c).Should(Equal(opt.Expected[i])) } return "TEST_RESULT", nil } // 原断言逻辑 casted, ok := v.(*[]T) if ok { Expect(*casted).Should(HaveLen(len(opt.Expected))) for i, c := range *casted { Expect(c).Should(Equal(opt.Expected[i])) } return "TEST_RESULT", nil } fmt.Printf("Type: %T\n", v) return v, nil }
总结
优先选择方法1(反射),它不依赖第三方库的内部实现,兼容性和稳定性最好;如果确认gosnowflake的内部类型不会变更,也可以临时使用方法2;如果有公开API可用,方法3是最优雅的选择。
内容的提问来源于stack exchange,提问作者Woody1193
相关产品推荐
相关产品推荐

