You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 09:18:00