亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

我如何應用單元測試來檢查 golang 的閏年?

我如何應用單元測試來檢查 golang 的閏年?

Go
江戶川亂折騰 2022-10-10 15:38:41
我想做單元測試并檢查日期是否是閏年,在這種情況下我如何應用單元測試,我不知道在這種情況下該怎么做?我已經創建了我的函數并且工作正常,我還有一個 JSON 文件,其中包含人員列表及其生日日期!希望能提供一些有關如何解決此問題的反饋或建議!謝謝BD.go: package mainimport (    "encoding/json"    "fmt"    "io/ioutil"    "log"    "os"    "time")// Users struct which contains// an array of userstype Users struct {    Users []User `json:"users"`}// User struct which contains a name// a type and a list of social linkstype User struct {    Firstname  string `json:"fname"`    Secondname string `json:"lname"`    Date       string `json:"date"`}var users Usersvar user Userfunc Birthday() {    // Open our jsonFile    jsonFile, err := os.Open("users.json")    // if we os.Open returns an error then handle it    if err != nil {        fmt.Println(err)    }    fmt.Println("Successfully Opened users.json")    // defer the closing of our jsonFile so that we can parse it later on    defer jsonFile.Close()    // read our opened xmlFile as a byte array.    byteValue, _ := ioutil.ReadAll(jsonFile)    // we initialize our Users array    // we unmarshal our byteArray which contains our    // jsonFile's content into 'users' which we defined above    json.Unmarshal(byteValue, &users)    IsLeapYear("users.json")}func IsLeapYear(user string) bool {    // we iterate through every user within our users array and    // print out the user Type, their name    for i := 0; i < len(users.Users); i++ {        date, err := time.Parse("2006/01/02", users.Users[i].Date)        if err != nil {            date, err = time.Parse("2006-01-02", users.Users[i].Date)            // date, err = time.Parse("2006 01 02", users.Users[i].Date)            if err != nil {                log.Fatal("unsupported date format:", err)            }        }
查看完整描述

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)

  }

}


查看完整回答
反對 回復 2022-10-10
?
胡子哥哥

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) bool

  • func 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 日相同。測試將證明是否是這種情況,然后您可以稍后依賴該功能。


查看完整回答
反對 回復 2022-10-10
  • 2 回答
  • 0 關注
  • 129 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號