Golang单元测试:JSON反序列化time.Time字段异常求助
问题:Go单元测试中JSON日期字段解析为零值(0001-01-01)
我正在为Go服务编写单元测试,尝试用以下JSON模拟数据:
[ { "Description": "Holiday 1", "HolidayDate": "2023-01-01T12:00:08+07:00" } ]
其中Description字段能正常解析,但HolidayDate字段解析后的值为0001-01-01 00:00:00 +0000 UTC。以下是我的代码,请问如何正确填充日期字段?
type Holiday struct { HolidayDate time.Time `json:"holidayDate"` Description string `json:"description"` } func Ptr1[T any](v T) *T { return &v } func getMockData() ([]entities.Holiday, error) { holidayFilePath := filepath.Join("../adapters/repositories/mocks/testData", "holidays.json") mockHolidays, err := UnmarshalFileData[entities.Holiday](holidayFilePath) if err != nil { return nil, fmt.Errorf(holidayFilePath, err) } return mockHolidays, nil } func UnmarshalFileData[T any](filePath string) ([]T, error) { var data []T myFile, err := os.Open(filePath) if err != nil { return data, err } defer myFile.Close() err = json.NewDecoder(myFile).Decode(&data) if err != nil { return data, err } return data, nil } func TestMocks(t *testing.T) { mockHolidays, err := getMockData() holiday := time.Date(2023, time.Month(1), 1, 00, 00, 00, 0, time.UTC) if err != nil { t.Fatal("error mocking holiday data:", err) } fmt.Println(mockHolidays[0].HolidayDate.String(), holiday.String()) assert.Equal(t, holiday.String(), mockHolidays[0].HolidayDate.String()) }
我尝试过多种JSON日期格式,但均未生效。
解决方案
1. 修正JSON标签与字段名的匹配问题
你的JSON中日期字段的键是HolidayDate(首字母大写),但结构体的JSON标签写的是holidayDate(首字母小写),导致encoding/json无法将JSON字段映射到结构体字段,因此HolidayDate被保留为time.Time的零值。
修改结构体的JSON标签,使其与JSON中的键完全一致:
type Holiday struct { HolidayDate time.Time `json:"HolidayDate"` // 改为大写H开头 Description string `json:"Description"` // 同步修正Description的标签,确保匹配 }
2. 调整测试断言的逻辑
修正标签后,JSON中的日期2023-01-01T12:00:08+07:00会被正确解析为time.Time类型,但该时间转换为UTC是2023-01-01 05:00:08 +0000 UTC,与你测试代码中创建的2023-01-01 00:00:00 +0000 UTC并不相等,断言会失败。
你可以选择两种方式调整:
- 直接使用解析后的时间作为期望:
// 解析后的UTC时间是2023-01-01 05:00:08 UTC expectedHoliday := time.Date(2023, time.January, 1, 5, 0, 8, 0, time.UTC) assert.Equal(t, expectedHoliday, mockHolidays[0].HolidayDate.UTC()) - 或者比较时间的本地化值(如果业务需要保留时区):
// 转换为+07:00时区的时间进行比较 loc, _ := time.LoadLocation("Asia/Bangkok") // +07:00对应的时区 expectedHoliday := time.Date(2023, time.January, 1, 12, 0, 8, 0, loc) assert.Equal(t, expectedHoliday, mockHolidays[0].HolidayDate)
3. 可选:自定义日期解析(针对非标准格式)
如果后续需要支持非RFC3339的日期格式,可以自定义类型并实现UnmarshalJSON方法:
type CustomTime time.Time func (ct *CustomTime) UnmarshalJSON(b []byte) error { s := strings.Trim(string(b), "\"") // 替换为你需要支持的日期格式 t, err := time.Parse("2006-01-02T15:04:05+07:00", s) if err != nil { return err } *ct = CustomTime(t) return nil } // 修改结构体字段类型 type Holiday struct { HolidayDate CustomTime `json:"HolidayDate"` Description string `json:"Description"` }
不过你的日期格式本身符合RFC3339标准,这一步不是必须的。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

