← 記事一覧へ

Go 学習記録(13):テスト

Go 基礎学習の第 13 回。単体テスト、テーブル駆動テスト、ベンチマークを整理します。

Go の単体テスト

1. 単体テストのケース

go test は、Go の命名と関数の形式に従って書かれたテストを実行します。

パッケージ内の _test.go で終わるファイルは、テスト用のビルドに含まれます。

通常の実行ファイルには含まれないため、詳しいテストを書いても本番バイナリは大きくなりません。

次の名前には、それぞれ異なる役割があります。

  1. Test:機能のテスト

  2. Benchmark:性能の測定

  3. Example:実行可能な例。ファズテストには Fuzz を使う

  4. TestMain:パッケージのテスト全体の準備と後処理

1.1. 単体テストを書く

単体テストの例を示します。

パッケージには、次の三つの Go ファイルがあります。

1、add.go

2、add_test.go

3、main.go

go

add.go では、二つの整数を加える Add 関数を定義します。

add_test.go は testing を読み込み、TestAdd で Add の結果を検証し、失敗を報告します。

import "testing"

func TestAdd(t *testing.T){
    re := add(1,2)
    if re!= 3{
        t.Errorf("add(1,2) = %d; want 3", re)
    }
}

パッケージのディレクトリで go test を実行し、結果を確認します。

1.2. 時間のかかるテストを省略する

短い実行モードなどでテストを省略したい場合は、t.Skip() を使います。

go test -short は短い実行モードを有効にします。実際に省略するには、各テストで testing.Short() を調べ、t.Skip() を呼び出します。

何を時間のかかるテストとするかは、テストを書く側が決めます。

省略する例を示します。

func TestAdd(t *testing.T){
    if testing.Short(){
        t.Skip("skip this test")
    }
    // 下面是执行不到的
    re := add(1,2)
    if re!= 3{
        t.Errorf("add(1,2) = %d; want 3", re)
    }
}

testing.Short() により、通常の実行と短い実行を区別できます。

2. テーブル駆動テスト

複数の入力を試す場合は、ケースを表にまとめ、同じ検証処理を各ケースで実行します。テストコードの重複を減らせます。

テーブル駆動テストの例を示します。

import "testing"

func TestAdd(t *testing.T){
    var tests = []struct{
        a int
        b int
        want int
    }{
        {1,2,3},
        {2,3,5},
        {3,4,7},
    }

    for _, tt := range tests{
        re := add(tt.a, tt.b)
        if re!= tt.want{
            t.Errorf("add(%d, %d) = %d; want %d", tt.a, tt.b, re, tt.want)
        }
    }
}

3. ベンチマーク

実行コストが重要な関数では、ベンチマークで性能を測定します。

ベンチマークも testing パッケージが提供します。

関数名は Benchmark で始め、その後に測定する処理の名前を付けます。

引数には *testing.B を受け取ります。

go test -bench . など、パターンを指定した go test -bench で実行します。

ベンチマークの例を示します。

import "testing"

func BenchmarkAdd(b *testing.B){
    a := 123
    b := 456
    c := 579


    for i:=0; i<b.N; i++{
        if actual := add(a,b); actual!= c{
            fmt.Printf("add(%d, %d) = %d; want %d", a, b, actual, c)
    }
}

b.ResetTimer() で計測をリセットし、準備に使った時間を測定から外せます。

この記事の日付について

旧サイトに記載された日付を保持しています。実際に書き始めた時期は、これより早い可能性があります。

同じシリーズ · Go の基礎学習

前の記事Go 学習記録(12):パッケージとモジュール ←