🧐

Goで特定のテストだけを実行したいのに別のテストも実行されてしまう??

2025/02/06に公開

はじめに

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

最後に

ドキュメントを読めばなんてことないですが、この現象に出会って初めて知ったので勉強になりました。
例えば別ファイルに同じテスト名が複数存在していると、本当は検証したいテストが通っているのに別ファイルのテストが失敗しているせいで意図しない結果が返ってくる、なんてこともありそうだなと思いました。
ぜひ参考にしてみてください!

参考記事

test package - cmd/go/internal/test

GitHubで編集を提案
株式会社StoreHero

Discussion