2 回答
TA贡献1810条经验 获得超5个赞
您的代码需要进行一些重构以使其可测试。目前您无法真正测试代码,因为代码中的函数不返回任何内容。在单元测试中,您调用一个函数并验证它的输出(一般来说)。
因此,为了使您的代码可测试,您必须在单独的函数中重构代码的某些部分。我将向您展示闰年的示例:
//main.go
func IsLeapYear(date time.Time) bool {
if date.Year() % 400 == 0 {
return true
}
return date.Year()%4 == 0 && date.Year()%100 != 0
}
在您的测试文件中:
//main_test.go
type dateTest struct {
date time.Time
expect bool
}
var dateTests = []dateTest{
// your test data
}
func TestIsLeapYear(t *testing.T){
for _, tc := range dateTests {
result := IsLeapYear(tc.data)
assert.Equal(t, tc.expect, result)
}
}
TA贡献1825条经验 获得超6个赞
关于您更新的代码:
我将从我给您的最重要的一条建议开始: 停止忽略错误!检查错误对于调试 Go 代码和运行程序绝对至关重要。请记住,与 Javascript 等许多高级语言不同,Go 没有例外。您对错误返回的检查是您必须捕获这些错误的唯一机会。
例如:
json.Unmarshal(byteValue, &users)
如果 json 无效,该行将返回错误。你应该检查一下。查找您使用的每个库函数的文档,但您没有记住 - 我会 - 并确保您正在使用这些错误消息。
好的,让我们看看你传递给什么IsLeapYear:
jsonFile, err := os.Open("users.json")
...
IsLeapYear("users.json")当你到达时,IsLeapYear你已经过了需要文件名的地步。您已经打开了该文件并将其值解组为一个Users结构。因此,您当然不需要将文件名传递给它。
让我强调一下 Pim 向您展示的一些您没有忠实遵循的内容:
func IsLeapYear(date time.Time) bool
IsLeapYearPim检查一个日期这一事实很重要。您的测试用例是需要单独检查的单独日期。但是您 IsLeapYear会遍历整个日期列表。您无法提供要检查的特定日期。您的闰年还希望收到多个日期,但您只返回一个bool,因此单个返回值不可能告诉您闰年检查您可能已经过去的多个日期的结果。
按照 Pim 的建议IsLeapYear- 它应该只有一个参数,并且应该是time.Time. 名字和姓氏不相关,IsLeapYear因此不需要传递。 IsLeapYear不需要解析日期 - 它们的格式与您在 json 中存储数据的方式有关,并且与它们所代表的日期是否是闰年无关。
瞄准 10-20 行功能。
我提出这个建议的原因是,长函数几乎总是做太多事情,这表明您需要重构函数以更好地匹配算法的组件。让我们将您的代码分解为伪代码以更好地反映您的算法:
从 json 文件中读取用户
对于每个用户:
打印用户信息
打印闰年消息
如果生日是今天,打印用户信息和生日信息
否则打印不是生日信息
从预期格式解析其日期
如果是闰年生日
否则打印用户信息而不是生日信息
从中我们可以确定我们可能编写的一些函数:
func ReadUsersFromJson(filename string) (*Users, err)func ParseUserDateString(date string) (time.Time, error)func IsLeapYear(date time.Time) boolfunc PrintUserInfo(u User)func IsTodaysDate(date time.Time) bool
这些功能中的每一个都非常简单明了,而且只做一件事。它们中的每一个都可以依次进行测试。你的一般测试方法很常见:写一个完整的输入列表(和预期的输出- 你错过了那部分),然后遍历列表,将每个输入传递给正在测试的函数,并验证它的结果是你的预期的。
因为ReadUsersFromJson您可能有一个tests/目录,其中包含您测试的一些 json 文件。您可以使用有效和无效的 json 测试成功和错误情况。
同样,ParseUserDateString测试数据可能类似于:
struct ParseUserDateStringTestData {
input string
expected time.Time
exp_err_msg string
}
然后你可以在那里测试成功和失败的案例。其余的功能依此类推。
一旦所有的功能都被编写和测试了,这只是一个将所有功能组装在一起的问题Birthday()。
func Birthday() {
users, err := ReadUsersFromJson("users.json")
if err != nil {
panic(fmt.Errorf("Failed to read from Json: %w", err))
}
for _, user := range users.Users {
if d, err := ParseUserDateString(user.Date); err != nil {
panic(fmt.Errorf("Date %s could not be parsed: %w", user.Date, err))
} else if IsLeapYear(d) {
PrintUserInfo(user)
fmt.Printf("Leap year message!")
if IsTodaysDate(d) {
fmt.Printf("birthday message!")
} else {
fmt.Printf("Not birthday message!")
}
} else {
fmt.Printf("Not leap year message!")
}
}
}
它恰好出现在 20 行,而且它在做什么也很清楚。您会注意到,自从我编写它以来,PrintUserInfo它删除了Birthday. 当然,这种重复使函数更难阅读和管理。
如果您编写像我列出的那样的函数,并测试所有这些函数,那么您的程序应该可以很好地结合在一起。请注意,main()或Birthday()不需要编写来测试其他功能。在编写函数时测试它们是一个好主意,以免最终积压大量测试,并灌输对您编写的代码的信心。
一个例子:
if date.Day() == time.Now().Day() {
我不认为那正在做你认为它正在做的事情。 Day()实际上是月份的日期,所以你实际上只是说,日期的日期与今天的日期是同一天吗?任何一个月Day()的 29 日都与 2 月 29 日相同。测试将证明是否是这种情况,然后您可以稍后依赖该功能。同样,ParseUserDateString测试数据可能类似于:
struct ParseUserDateStringTestData {
input string
expected time.Time
exp_err_msg string
}
然后你可以在那里测试成功和失败的案例。其余的功能依此类推。
一旦所有的功能都被编写和测试了,这只是一个将所有功能组装在一起的问题Birthday()。
func Birthday() {
users, err := ReadUsersFromJson("users.json")
if err != nil {
panic(fmt.Errorf("Failed to read from Json: %w", err))
}
for _, user := range users.Users {
if d, err := ParseUserDateString(user.Date); err != nil {
panic(fmt.Errorf("Date %s could not be parsed: %w", user.Date, err))
} else if IsLeapYear(d) {
PrintUserInfo(user)
fmt.Printf("Leap year message!")
if IsTodaysDate(d) {
fmt.Printf("birthday message!")
} else {
fmt.Printf("Not birthday message!")
}
} else {
fmt.Printf("Not leap year message!")
}
}
}
它恰好出现在 20 行,而且它在做什么也很清楚。您会注意到,自从我编写它以来,PrintUserInfo它删除了Birthday. 当然,这种重复使函数更难阅读和管理。
如果您编写像我列出的那样的函数,并测试所有这些函数,那么您的程序应该可以很好地结合在一起。请注意,main()或Birthday()不需要编写来测试其他功能。在编写函数时测试它们是一个好主意,以免最终积压大量测试,并灌输对您编写的代码的信心。
一个例子:
if date.Day() == time.Now().Day() {
我不认为那正在做你认为它正在做的事情。 Day()实际上是月份的日期,所以你实际上只是说,日期的日期与今天的日期是同一天吗?任何一个月Day()的 29 日都与 2 月 29 日相同。测试将证明是否是这种情况,然后您可以稍后依赖该功能。
- 2 回答
- 0 关注
- 189 浏览
添加回答
举报
