Testing Package

Golangの標準パッケージにある自動テストのためのもの ベンチマークを行うこともできる。

go test <target package>コマンドでテストを実行できる。

公式サイト

サンプルコード


import (
  "testing"
  "github.com/stretchr/testify/assert"
)

// テスト用の関数
func TestApple() {
  fmt.Println("Give me Apple")
}

func Example(t *testing.T) {
  correct := 42
  answer := TestTarget(100)
  if correct != answer {
    // テストに失敗
    t.Errorf("Bad answer... correct=%d, answer=%d", correct, answer)
  }

  // 標準ではアサート関数は用意されていないので
  // testifyというライブラリを使うといい
  assert.Equal(t, correct, answer, "Bad answer...")

  // サブテストの実行
  t.Run("Case=A", func(t *testing.T){  })
  t.Run("Case=A", func(t *testing.T){  })
  t.Run("Case=B", func(t *testing.T){  })
}

func SkipTest(t *testing.T) {
  t.Skip()
}

基本的な使い方

go testコマンドを実行するためには以下の項目を満たす必要がある。

  • "_test.go"で終わるファイルの作成。
    • このファイルはビルドの時に自動的に省かれる。
  • 上のファイルの中で関数名が大文字から始まる関数がテスト内容として実行される。
    • \*testing.Tを引数に取ることができる。
  • テスト失敗を告げるにはError, Failまたは関係するメソッドを使う。
  • `*testing.T`のSkipメソッドを使うとそのテストをスキップできる。

ベンチマーク

ベンチマークを行う際は以下の項目を追加で満たす必要がある。

  • go test-benchフラグを付ける
  • ベンチマークを行う関数はBenchmarkXxx(*testing.B)という形式を取る
    • Benchmarkの後に大文字から始まる名前を付けること
    • \*testing.Bを引数に取ることができる。
      • \*testing.Tと同様Skip関数が使える。

サブテスト

Runメソッドを使うことで実行される関数内でサブテスト/サブベンチマーク(以降サブテストと統一)を行うことができる

サブテストには名前を付けることができ、付けた名前は後述する-runオプションなどで利用できる。

ネストすることも可能で、Runメソッド内でRunメソッドを呼び出すとできる。

テストの前準備/後処理

テストする前に追加の前準備/後処理が必要になるケースがある場合は、テスト用ファイル内に、func TestMain(m *testing.M)を定義するといい。

定義した時は各テスト関数は直接呼び出されず、代わりにTestMain関数が呼び出される。 その際はTestMain関数内でm.Run()の結果をos.Exit()に渡すこと。

func TestMain(m *testing.M) {
  // コマンドライン引数を使用したい時は先にflag.Parse()を呼び出すこと
    os.Exit(m.Run())
}

ドキュメントだけでは使い方がよくわからなかったので、Githubで調べたところ、以下のパターンで使われていた。

  1. ドキュメントどおり
    func TestMain(m *testing.M) {
      os.Exit(m.Run);
    }
    // 変数に介するパターン
    func TestMain(m *testing.M) {
      r := m.Run()
      os.Exit(r);
    }
    
  2. mを他の関数に渡し、その中で色々する ここから拝借
    func hoge(m *testing.M) {
      defer testhelper.MustHaveNoChildProcess()
    
      m.Run()
    }
    
  3. 変わったものも 初め見た時戸惑ったが、goroutineを使っているコードもあった こちらから
    func Test_main(t *testing.T) {
        go main()
        exitCode = <-exitCh
    }
    func TestMain(m *testing.M) {
        m.Run()
        // can exit because cover profile is already written
        os.Exit(exitCode)
    }
    
    go main()はgoroutineというGolangの軽量スレッド内でmain関数を呼び出すという意味になるみたいGoroutines その下の<-exitChもgoroutine関連でChannelsと呼ばれる値の送受信のための型だそうだ

-runオプション

-runオプションを使うとファイル内の特定の関数/サブテストのみ実行できる。

以下、ドキュメントから拝借した。

go test -run ''      # Run all tests.
go test -run Foo     # Run top-level tests matching "Foo", such as "TestFooBar".
go test -run Foo/A=  # For top-level tests matching "Foo", run subtests matching "A=".
go test -run /A=1    # For all top-level tests, run subtests matching "A=1".```

補足事項

補足事項として以下のものがある

  • go test ./...を使うとプロジェクト内の全てのパッケージのテストを行える
    • ただし、バージョン1.9以降から
    • それ以前のバージョンのときは go test $(go list ./... | grep -v /vendor/)と入力するといい
  • テストデータは"testdata"と名付けられたディレクトリに入れる
    • そのディレクトリはgoツールから無視される仕様になっている
  • 標準エラー出力に何かを出力しても標準出力へ出力される
    • これは仕様で、goコマンドの標準エラーはテストをビルドした時のエラー出力に使われている