Go のテスト基礎 - testing パッケージと go test
Go には標準ライブラリに testing パッケージが組み込まれており、外部ツールなしでテストを書いて実行できる。他の言語では JUnit や pytest のようなフレームワークを別途導入する必要があるが、Go ではそうした手間がない。
テストファイルの命名規則
テストコードは _test.go というサフィックスを持つファイルに書く。たとえば math.go に対するテストは math_test.go になる。この命名規則により、go build 時にはテストファイルが自動的に除外され、go test 時にだけコンパイル対象になる。
// math.go
package calc
func Add(a, b int) int {
return a + b
}対応するテストファイルは次のようになる。
// math_test.go
package calc
import "testing"
func TestAdd(t *testing.T) {
got := Add(2, 3)
want := 5
if got != want {
t.Errorf("Add(2, 3) = %d, want %d", got, want)
}
}テスト関数は必ず Test で始まり、引数に *testing.T を受け取る。この規則を守らないと go test がテスト関数として認識しない。
go test コマンド
テストの実行は go test コマンドで行う。カレントパッケージのテストを実行する場合はそのまま叩けばいい。
# カレントパッケージのテストを実行
go test
# 詳細な出力を表示
go test -v
# プロジェクト全体のテストを実行
go test ./...-v フラグを付けると各テスト関数の名前と結果が個別に表示される。デフォルトでは失敗したテストだけが出力されるため、すべてパスした場合は ok とだけ表示される。
失敗時のみ詳細を出力。成功なら ok の一行だけ
すべてのテスト関数の名前・結果・ログを個別に出力
t.Errorf と t.Fatalf の使い分け
テストが期待と異なる結果を返したとき、報告の方法は大きく2つある。t.Errorf はエラーを記録するが、テスト関数の残りの処理は続行する。一方 t.Fatalf はエラーを記録した直後にそのテスト関数を中断する。
func TestDivide(t *testing.T) {
result, err := Divide(10, 0)
if err == nil {
t.Fatalf("expected error for division by zero, got nil")
}
// t.Fatalf で中断されるので、ここには到達しない
result, err = Divide(10, 2)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if result != 5 {
t.Errorf("Divide(10, 2) = %f, want 5", result)
}
}後続の処理が前提条件に依存する場合は t.Fatalf を使い、独立した検証であれば t.Errorf で続行させるのが一般的だ。
複数の独立したアサーションを1つの関数内で行いたいとき。すべての失敗を一度に確認できる。
前提条件が崩れたら後続の検証が無意味になるとき。nil チェックや初期化エラーの検出など。
テストの実行パターン
特定のテスト関数だけを実行したい場合は -run フラグを使う。正規表現でマッチするテスト関数を絞り込める。
# TestAdd だけを実行
go test -v -run TestAdd
# "Divide" を含むテスト関数を実行
go test -v -run Divideまた、テストにはキャッシュが効く仕組みになっている。ソースコードに変更がなければ前回の結果がそのまま使われ、(cached) と表示される。キャッシュを無視して再実行したい場合は -count=1 を付ける。
# キャッシュを無視して実行
go test -count=1 ./...テスト失敗時のメッセージ設計
テストが失敗したときのメッセージは、何が起きたのかを素早く理解できるように書く。Go のコミュニティでは got と want を使った形式が広く使われている。
if got != want {
t.Errorf("Add(%d, %d) = %d, want %d", a, b, got, want)
}関数名、入力値、実際の出力、期待値をすべて含めることで、失敗時にログを見ただけで原因を特定できる。曖昧なメッセージは避けるべきだ。
t.Errorf("test failed") - 何が失敗したのか分からない
t.Errorf("Add(2, 3) = %d, want %d", got, want) - 入力・出力・期待値が明確
testing パッケージは小さな API でありながら、Go のテスト文化を支える基盤になっている。外部ライブラリに頼らず、標準の仕組みだけで十分に実用的なテストが書ける点が Go らしい設計思想と言えるだろう。