テストを追加する

コードが安定した状態になったので(ところで、よくできました)、テストを追加しましょう。開発中にコードをテストすることで、変更を加える際に紛れ込む可能性のあるバグを検出できます。このトピックでは、Hello関数のテストを追加します。

Goのユニットテストの組み込みサポートにより、開発中のテストが簡単になります。具体的には、命名規則、Goのtestingパッケージ、およびgo testコマンドを使用することで、テストを迅速に記述して実行できます。

  1. greetingsディレクトリに、greetings_test.goというファイルを作成します。

    ファイル名の末尾が_test.goであることは、go testコマンドに、このファイルにテスト関数が含まれていることを伝えます。

  2. greetings_test.goに、次のコードを貼り付けて保存します。
    package greetings
    
    import (
        "testing"
        "regexp"
    )
    
    // TestHelloName calls greetings.Hello with a name, checking
    // for a valid return value.
    func TestHelloName(t *testing.T) {
        name := "Gladys"
        want := regexp.MustCompile(`\b`+name+`\b`)
        msg, err := Hello("Gladys")
        if !want.MatchString(msg) || err != nil {
            t.Fatalf(`Hello("Gladys") = %q, %v, want match for %#q, nil`, msg, err, want)
        }
    }
    
    // TestHelloEmpty calls greetings.Hello with an empty string,
    // checking for an error.
    func TestHelloEmpty(t *testing.T) {
        msg, err := Hello("")
        if msg != "" || err == nil {
            t.Fatalf(`Hello("") = %q, %v, want "", error`, msg, err)
        }
    }
    

    このコードでは、

    • テストするコードと同じパッケージにテスト関数を実装します。
    • greetings.Hello関数をテストするための2つのテスト関数を作成します。テスト関数名は、TestNameという形式です。ここで、Nameは特定のテストについて何かを述べています。また、テスト関数は、testingパッケージのtesting.Tへのポインタをパラメータとして受け取ります。このパラメータのメソッドは、テストからのレポートとログに使用します。
    • 2つのテストを実装します
      • TestHelloNameHello関数を呼び出し、関数が有効な応答メッセージを返すことができるはずの名前値を渡します。呼び出しがエラーまたは予期しない応答メッセージ(渡した名前を含まないメッセージ)を返した場合、tパラメータのFatalfメソッドを使用してコンソールにメッセージを出力し、実行を終了します。
      • TestHelloEmptyは、空の文字列を使用してHello関数を呼び出します。このテストは、エラー処理が機能することを確認するように設計されています。呼び出しが空でない文字列またはエラーなしを返した場合、tパラメータのFatalfメソッドを使用してコンソールにメッセージを出力し、実行を終了します。
  3. 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
    
  4. 失敗するテストを表示するために、greetings.Hello関数を壊します。

    TestHelloNameテスト関数は、Hello関数のパラメータとして指定した名前の戻り値をチェックします。失敗するテスト結果を表示するには、greetings.Hello関数を変更して、名前を含まないようにします。

    greetings/greetings.goで、Hello関数の代わりに次のコードを貼り付けます。ハイライト表示された行は、name引数が誤って削除されたかのように、関数が返す値を変更します。

    // Hello returns a greeting for the named person.
    func Hello(name string) (string, error) {
        // If no name was given, return an error with a message.
        if name == "" {
            return name, errors.New("empty name")
        }
        // Create a message using a random format.
        // message := fmt.Sprintf(randomFormat(), name)
        message := fmt.Sprint(randomFormat())
        return message, nil
    }
    
  5. greetingsディレクトリのコマンドラインで、go testを実行してテストを実行します。

    今回は、-vフラグなしでgo testを実行します。出力には、失敗したテストの結果のみが含まれます。これは、多数のテストがある場合に役立ちます。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
    

次の(そして最後の)トピックでは、コードをコンパイルしてローカルで実行する方法について説明します。