Go中测试数据转换函数需显式定义输入-输出对,覆盖正常映射、缺失字段、类型不匹配、空值及嵌套结构;用reflect.DeepEqual比较同类型值,单独验证时间/数字等易错类型,并通过helper函数统一断言逻辑。

在 Go 中测试数据转换函数,核心是验证输入到输出的映射是否严格符合预期:字段值正确、类型精确、空值/边界情况处理得当、错误路径可捕获。不依赖运行时反射推断,而是用显式声明的测试用例覆盖结构和语义。
定义清晰的输入-输出对,覆盖典型与边界场景
为每个转换函数准备一组结构化测试用例,每个用例包含原始输入(如 map[string]interface{} 或 JSON 字节)、期望输出(目标 struct 实例)和可选的期望错误。重点覆盖:
- 正常字段映射(字符串转 int、时间字符串转 time.Time)
- 缺失字段(struct 字段应有合理零值或返回 error)
- 类型不匹配(如 "abc" 转 int → 应失败而非静默转成 0)
- 空值/nil 输入(如 nil map、空 JSON)
- 嵌套结构或切片转换(确保深层字段也被校验)
使用 reflect.DeepEqual 验证结构一致性,但先确保类型安全
不要直接用 reflect.DeepEqual 比较 interface{} —— 它可能掩盖底层类型差异(比如 json.Number 和 float64 在 DeepEqual 中相等,但业务上不应混用)。正确做法:
- 将输入解析为明确类型(如 json.Unmarshal 到 map[string]json.RawMessage)
- 调用转换函数得到目标 struct
- 用 reflect.DeepEqual 比较该 struct 与预定义的期望 struct 值(二者类型完全一致)
- 若需验证错误,检查 error 是否为预期类型(如 errors.Is(err, ErrInvalidField))或消息是否匹配(t.Log(err) + 字符串断言)
为时间、数字等易出错类型单独编写转换验证逻辑
标准库的 time.Parse 或 strconv.Atoi 在失败时返回 error,但转换函数常封装了默认行为(如忽略错误、设零值),这会掩盖问题。测试中应:
立即学习“go语言免费学习笔记(深入)”;
- 传入非法时间字符串("2023-13-01")、溢出数字("99999999999999999999")
- 确认函数返回非 nil error,且 error 包含足够上下文(如字段名:"failed to parse 'created_at': parsing time...")
- 避免在转换函数里用 strconv.FormatInt(int64(x), 10) 这类隐式类型转换;测试要能暴露 int32 被误转为 int64 导致精度丢失的问题
利用 test helper 函数统一断言逻辑,减少样板代码
把重复的反序列化→转换→比较流程封装成 helper,例如:
func TestConvertUser(t *testing.T) {tests := []struct {
name string
input []byte // JSON input
want User
wantErr bool
}{
{"valid", []byte(`{"id":1,"name":"Alice"}`), User{ID: 1, Name: "Alice"}, false},
{"invalid_id", []byte(`{"id":"x"}`), User{}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ConvertUserJSON(tt.input)
if (err != nil) != tt.wantErr {
t.Fatalf("ConvertUserJSON() error = %v, wantErr %v", err, tt.wantErr)
}
if !tt.wantErr && !reflect.DeepEqual(got, tt.want) {
t.Errorf("ConvertUserJSON() = %v, want %v", got, tt.want)
}
})
}
}










