如何使用Golang编写单元测试验证日期是否为闰年
闰年校验功能单元测试编写指导
以下是可直接落地的问题排查、代码优化和测试编写方案:
一、现有代码问题排查
- 闰年判断逻辑错误:当前代码用
date.Day()(日期的日字段)判断闰年,正确逻辑应该判断date.Year()(年份) - 函数耦合度极高:
IsLeapYear依赖全局变量users,入参设计不合理(当前声明入参为string类型但实际没用,测试代码直接传time.Time类型根本跑不通) - 结构体JSON标签不匹配:
User结构体的Firstname标签为json:"fname",但json文件里的key是大写Fname,会导致解析失败取不到值 - users.json语法错误:倒数第6行多了一个闭合的
},会导致解析报错 - 硬编码依赖文件路径:单元测试运行时工作目录可能和运行时不一致,硬编码
users.json路径会导致测试找不到文件
二、代码优化方案
先解耦功能,把纯逻辑和IO操作拆分,方便单测:
1. 抽离纯闰年判断函数
// 判断指定年份是否为闰年,纯逻辑无依赖,非常适合单元测试 func IsLeapYear(year int) bool { return year%400 == 0 || (year%4 == 0 && year%100 != 0) }
2. 拆分日期解析、用户读取逻辑
// 解析支持两种格式的日期字符串 func ParseBirthday(dateStr string) (time.Time, error) { date, err := time.Parse("2006/01/02", dateStr) if err == nil { return date, nil } return time.Parse("2006-01-02", dateStr) } // 从指定路径读取用户列表 func LoadUsers(filePath string) (Users, error) { jsonFile, err := os.Open(filePath) if err != nil { return Users{}, err } defer jsonFile.Close() byteValue, err := ioutil.ReadAll(jsonFile) if err != nil { return Users{}, err } var users Users err = json.Unmarshal(byteValue, &users) return users, err } // 单独抽出生日判断逻辑,方便mock当前时间做测试 func IsBirthdayToday(birthday time.Time, now time.Time) bool { return birthday.Month() == now.Month() && birthday.Day() == now.Day() }
3. 修正User结构体标签
type User struct { Firstname string `json:"Fname"` // 标签改为和JSON文件一致的大写F Secondname string `json:"Lname"` // 同理改大写L Date string `json:"date"` }
4. 修正users.json的语法错误
删除倒数第6行多余的}即可。
三、单元测试编写方案
1. 纯逻辑函数的单元测试
针对抽离的IsLeapYear、ParseBirthday、IsBirthdayToday这几个无外部依赖的函数编写测试用例,覆盖所有边界场景:
package main import ( "testing" "time" "github.com/stretchr/testify/assert" ) func TestIsLeapYear(t *testing.T) { testCases := []struct { year int want bool }{ {2000, true}, // 能被400整除是闰年 {1900, false}, // 能被100整除但不能被400整除不是闰年 {2020, true}, // 能被4整除不能被100整除是闰年 {2023, false}, // 不能被4整除不是闰年 {1988, true}, // 覆盖json文件中的1988/02/29场景 } for _, tc := range testCases { got := IsLeapYear(tc.year) assert.Equal(t, tc.want, got, "year %d judge error", tc.year) } } func TestParseBirthday(t *testing.T) { testCases := []struct { dateStr string want time.Time wantErr bool }{ {"1982/01/08", time.Date(1982, 1, 8, 0,0,0,0, time.UTC), false}, {"1991-03-28", time.Date(1991,3,28,0,0,0,0, time.UTC), false}, {"1995.05.24", time.Time{}, true}, // 不支持的格式返回错误 } for _, tc := range testCases { got, err := ParseBirthday(tc.dateStr) if tc.wantErr { assert.Error(t, err) continue } assert.NoError(t, err) assert.Equal(t, tc.want, got) } } func TestIsBirthdayToday(t *testing.T) { now := time.Date(2024, 3, 8, 0,0,0,0, time.UTC) testCases := []struct { birthday time.Time want bool }{ {time.Date(1986,3,8,0,0,0,0, time.UTC), true}, // 月日相同返回true {time.Date(1986,3,9,0,0,0,0, time.UTC), false}, // 日不同返回false {time.Date(1986,4,8,0,0,0,0, time.UTC), false}, // 月不同返回false } for _, tc := range testCases { got := IsBirthdayToday(tc.birthday, now) assert.Equal(t, tc.want, got) } }
2. 集成测试(读取JSON文件场景)
准备测试专用的小JSON文件放在testdata目录下(Go测试会自动忽略testdata目录),测试LoadUsers函数是否能正确读取解析文件内容:
func TestLoadUsers(t *testing.T) { // 测试正常文件读取 users, err := LoadUsers("testdata/test_users.json") assert.NoError(t, err) assert.Len(t, users.Users, 2) // 测试文件里预设2个用户 assert.Equal(t, "Johnny", users.Users[0].Firstname) // 测试不存在的文件场景 _, err = LoadUsers("testdata/nonexist.json") assert.Error(t, err) }
内容的提问来源于stack exchange,提问作者karim Salim
相关产品推荐
相关产品推荐

