Goで特定のテストだけを実行したいのに別のテストも実行されてしまう??
はじめに
Go で特定のテストのみを実行したい時には run オプションを使うことで実行できます。
$ go test -run テスト関数名
しかし場合によっては別のテストも一緒に実行されてしまう時があります。
特に機能が増えてくるとその分テストも増えるため、様々なテスト名が混在することになりこの挙動が発生することもあると思います。
run オプションについて理解しておくと「なぜこのような挙動になるのか」「どうしたら回避できるのか」を知ることに繋がります。
今回はこのあたりの調査をしてみました。
結論
run オプションはドキュメントからも分かるように正規表現で「特定のテスト」を認識して実行します。
$ go test -v -run regexp
そのため 1 ユーザーを取得する「TestGetUser」とユーザー一覧を取得する「TestGetUsers」というテスト名が存在する場合に「TestGetUser」だけを実行しようと次のコマンドを打つと両方のテストが実行されてしまいます。
$ go test -v -run TestGetUser
package main
import "testing"
func TestGetUser(t *testing.T) {
t.Log(">>>>> TestGetUserだよ")
}
func TestGetUsers(t *testing.T) {
t.Log(">>>>> TestGetUsersだよ")
}
テスト結果(両方のテストが実行される)
=== RUN TestGetUser
sample_test.go:6: >>>>> TestGetUserだよ
--- PASS: TestGetUser (0.00s)
=== RUN TestGetUsers
sample_test.go:10: >>>>> TestGetUsersだよ
--- PASS: TestGetUsers (0.00s)
PASS
ok sample 0.169s
これを防ぐには次のような正規表現を使うと「TestGetUser」のみを実行できます。
$ go test -v -run '^TestGetUser$'
テスト結果(TestGetUser のみが実行される)
=== RUN TestGetUser
sample_test.go:6: >>>>> TestGetUserだよ
--- PASS: TestGetUser (0.00s)
PASS
ok sample 0.335s
特定のサブテストのみを実行したい
特定のサブテストを実行したい場合は次のようにスラッシュ (/) で区切ると指定できます。
これは正規表現が分割されて X に一致するテスト、Y に一致するテスト、というふうに複数の条件でマッチングできるためです。
また Y にマッチするサブテストがあるかどうかを調べるため、X に一致するすべてのテストが実行される点は覚えておくと良いと思います。
$ go test -v -run X/Y
そのため 「TestGetUser」 と 「TestGetUser1」 を実行したい場合に次のような指定をすると X の正規表現に一致する 「TestGetUsers」 も実行されてしまいます。
$ go test -v -run TestGetUser/TestGetUser1
package main
import "testing"
func TestGetUser(t *testing.T) {
t.Log(">>>>> TestGetUserだよ")
t.Run("TestGetUser1", func(t *testing.T) {
t.Log(">>>>> TestGetUser1だよ")
})
t.Run("TestGetUser2", func(t *testing.T) {
t.Log(">>>>> TestGetUser2だよ")
})
}
func TestGetUsers(t *testing.T) {
t.Log(">>>>> TestGetUsersだよ")
}
テスト結果(TestGetUsers も実行されてしまう)
=== RUN TestGetUser
sample_test.go:6: >>>>> TestGetUserだよ
=== RUN TestGetUser/TestGetUser1
sample_test.go:11: >>>>> TestGetUser1だよ
--- PASS: TestGetUser (0.00s)
--- PASS: TestGetUser/TestGetUser1 (0.00s)
=== RUN TestGetUsers
sample_test.go:16: >>>>> TestGetUsersだよ
--- PASS: TestGetUsers (0.00s)
PASS
ok sample 0.172s
これを回避するには次のような正規表現を使うと親である「TestGetUser」とサブテスト「TestGetUser1」のみが実行されるようになります。
go test -v -run '^TestGetUser$/TestGetUser1'
テスト結果(TestGetUser と TestGetUser1 が実行される)
=== RUN TestGetUser
sample_test.go:6: >>>>> TestGetUserだよ
=== RUN TestGetUser/TestGetUser1
sample_test.go:11: >>>>> TestGetUser1だよ
--- PASS: TestGetUser (0.00s)
--- PASS: TestGetUser/TestGetUser1 (0.00s)
PASS
ok sample 0.426s
最後に
ドキュメントを読めばなんてことないですが、この現象に出会って初めて知ったので勉強になりました。
例えば別ファイルに同じテスト名が複数存在していると、本当は検証したいテストが通っているのに別ファイルのテストが失敗しているせいで意図しない結果が返ってくる、なんてこともありそうだなと思いました。
ぜひ参考にしてみてください!
Discussion