paralleltest

Table of Contents

  1. 解決する問題
  2. 設定
  3. オプション
  4. サンプル
    1. 検出例
    2. 修正例
  5. 注意点
  6. 参考リンク

paralleltest はテスト関数で t.Parallel() の呼び出しが不足していないかをチェックするツールです。

解決する問題

Go のテストはデフォルトで同一パッケージ内のテストが逐次実行されます。t.Parallel() を呼ぶことで並列実行が可能になり、テストスイート全体の実行時間を短縮できます。呼び忘れを検出して並列実行を促進します。

1
2
3
4
5
6
7
8
9
10
11
12
// Before: t.Parallel() がない → テストが逐次実行される
func TestCreateUser(t *testing.T) {
// このテストは前のテストの完了を待つ
user := createTestUser(t)
assert.NotEmpty(t, user.ID)
}

func TestDeleteUser(t *testing.T) {
// このテストも前のテストの完了を待つ
err := deleteTestUser(t, "123")
assert.NoError(t, err)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// After: t.Parallel() を追加 → テストが並列実行される
func TestCreateUser(t *testing.T) {
t.Parallel()

user := createTestUser(t)
assert.NotEmpty(t, user.ID)
}

func TestDeleteUser(t *testing.T) {
t.Parallel()

err := deleteTestUser(t, "123")
assert.NoError(t, err)
}

設定

公式ドキュメント

1
2
3
4
5
6
7
8
9
10
# .golangci.yml 設定例
version: "2"

linters:
enable:
- paralleltest
settings:
paralleltest:
ignore-missing: false
ignore-missing-subtests: false

オプション

オプション デフォルト 説明
ignore-missing bool false t.Parallel() の欠落を無視し、誤った使い方のみ報告する
ignore-missing-subtests bool false サブテストでの t.Parallel() 欠落を無視する(トップレベルテストのみチェック)

サンプル

検出例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// paralleltest が警告するパターン

// 1. トップレベルテストに t.Parallel() がない
func TestFetch(t *testing.T) { // Function TestFetch missing the call to method parallel
result := Fetch("https://example.com")
assert.NotNil(t, result)
}

// 2. サブテストに t.Parallel() がない
func TestProcess(t *testing.T) {
t.Parallel()

tests := []struct {
name string
input int
}{
{"positive", 1},
{"negative", -1},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { // Range statement for test ... does not call t.Parallel()
result := Process(tt.input)
assert.NotZero(t, result)
})
}
}

修正例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func TestFetch(t *testing.T) {
t.Parallel()

result := Fetch("https://example.com")
assert.NotNil(t, result)
}

func TestProcess(t *testing.T) {
t.Parallel()

tests := []struct {
name string
input int
}{
{"positive", 1},
{"negative", -1},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

result := Process(tt.input)
assert.NotZero(t, result)
})
}
}

注意点

  • 共有リソース(DB、ファイル、グローバル変数)に依存するテストは並列化するとデータ競合が発生する。その場合は //nolint:paralleltest // 共有 DB を使用 で抑制する
  • ignore-missing-subtests: true にすると、サブテストの並列化は任意にできる。段階的な導入に便利
  • テーブルドリブンテストでサブテストを並列化する場合、Go 1.22 以降ではループ変数のキャプチャ問題が解消されている

参考リンク