• English
  • 加入測試

    現在你的程式碼已經穩定(幹得漂亮),接下來加入一個測試。在開發過程中測試程式碼可以發現隨著修改而引入的 bug。本文中,你將為 Hello 函數加入一個測試。

    注意: 本文是系列教學的一部分,該系列始於 建立 Go 模組

    Go 語言內建的單元測試支援使得在開發過程中進行測試變得更加容易。具體來說,透過使用命名約定、Go 的 testing 套件以及 go test 命令,你可以快速撰寫和執行測試。

    步驟

    1. 建立測試檔案,在 greetings 目錄中建立一個名為 greetings_test.go 的檔案。

    檔名以 _test.go 結尾,這會告知 go test 命令該檔案包含測試函數。

    1. 將以下程式碼貼上greetings_test.go 並儲存檔案:
    package greetings
    
    import (
        "testing"
        "regexp"
    )
    
    // TestHelloName 使用名稱呼叫 greetings.Hello,檢查返回值是否有效。
    func TestHelloName(t *testing.T) {
        name := "Gladys"
        want := regexp.MustCompile(`\b`+name+`\b`)
        msg, err := Hello("Gladys")
        if !want.MatchString(msg) || err != nil {
            t.Errorf(`Hello("Gladys") = %q, %v, want match for %#q, nil`, msg, err, want)
        }
    }
    
    // TestHelloEmpty 使用空字串呼叫 greetings.Hello,檢查是否返回錯誤。
    func TestHelloEmpty(t *testing.T) {
        msg, err := Hello("")
        if msg != "" || err == nil {
            t.Errorf(`Hello("") = %q, %v, want "", error`, msg, err)
        }
    }

    在這段程式碼中,你:

    • 在與其測試程式碼相同的套件中實作測試函數。
    • 建立兩個測試函數來測試 greetings.Hello 函數。測試函數名稱的形式為 TestName,其中 Name 描述了特定測試的內容。此外,測試函數接受一個指向 testing 套件中的 testing.T 類型的指標作為參數。你使用這個參數的 methods 來報告和記錄測試中的資訊。
    • 實作了兩個測試:
      • TestHelloName:使用一個 name 值呼叫 Hello 函數,並檢查是否有有效的回應訊息。如果呼叫返回錯誤或意外的回應訊息(不包含你傳入的名字),則使用 t 參數的 Errorf 方法在主控台列印一條訊息。
      • TestHelloEmpty:使用空字串呼叫 Hello 函數,以確認錯誤處理。如果呼叫返回非空字串或沒有錯誤,則使用 t 參數的 Errorf 方法在主控台列印一條訊息。
    1. 從命令列執行測試,在 greetings 目錄中使用 go test 命令

    go test 命令會執行測試檔案(檔名以 _test.go 結尾)中的測試函數(函數名以 Test 開頭)。你可以加入 -v 標誌以取得詳細輸出,列出所有測試及其結果。

    測試應該通過:

    $ go test
    PASS
    ok      example.com/greetings   0.364s
    
    $ go test -v
    === RUN   TestHelloName
    --- PASS: TestHelloName (0.00s)
    === RUN   TestHelloEmpty
    --- PASS: TestHelloEmpty (0.00s)
    PASS
    ok      example.com/greetings   0.372s
    1. 破壞 Hello 函數 以查看失敗的測試:

    TestHelloName 測試檢查返回值是否包含你指定的名字。為了查看失敗的測試結果,修改 Hello 函數,使其回應中不包含名字。

    greetings/greetings.go 中,將 Hello 函數替換為以下程式碼(注意高亮部分):

    // Hello 返回指定人的問候語。
    func Hello(name string) (string, error) {
        // 如果沒有提供名字,則返回帶有訊息的錯誤。
        if name == "" {
            return name, errors.New("empty name")
        }
        // 使用隨機格式建立訊息。
        // message := fmt.Sprintf(randomFormat(), name)
        message := fmt.Sprint(randomFormat())
        return message, nil
    }
    1. 再次執行測試greetings 目錄中:

    這次執行 go test 時不加 -v 標誌。輸出將僅顯示失敗測試的結果,這在你有很多測試時非常有用。TestHelloName 測試應該失敗,而 TestHelloEmpty 仍然通過。

    $ go test
    --- FAIL: TestHelloName (0.00s)
        greetings_test.go:15: Hello("Gladys") = "Hail, %v! Well met!", <nil>, want match for `\bGladys\b`, nil
    FAIL
    exit status 1
    FAIL    example.com/greetings   0.182s

    總結

    你現在為 Go 程式碼撰寫並執行了測試,學會了如何使用 Go 內建的測試框架來確保你的函數按預期行為。這種做法有助於保持程式碼品質,並在開發早期捕獲 bug。

    在接下來的(也是最後一個)主題中,你將看到如何編譯和安裝程式碼以便在本地執行。