メインコンテンツへスキップ

Go Proposal Weekly Digest

Go言語のproposal更新を毎週お届け

#77320active

testing/synctest: add Subtest function

新規提案

要約

AIによる要約であり、誤りを含む場合があります。

概要

testing/synctest パッケージに Subtest 関数を追加する提案です。これは testing.T.Runsynctest.Test を組み合わせたショートカット関数であり、テーブル駆動テスト(table-driven test)でのコードのネスト(字下げ)を1段階削減することを目的としています。

ステータス変更

(なし)active
2026年5月27日に開催されたProposal Review Meeting(@adonovan, @bradfitz, @cherrymui, @griesemer, @ianlancetaylor, @neild, @rolandshoemaker が参加)において、このプロポーザルが「active」カラムに追加され、週次レビューの対象となりました。@griesemer は「議論の余地は少ないが、必要性が明確かどうかは不明」とコメントしており、引き続き議論が進められている段階です。

技術的背景

現状の問題点

testing/synctest パッケージの Test 関数はバブル(bubble)と呼ばれる独立した時間制御環境を作成しますが、サブテストを書く際に t.Runsynctest.Test を組み合わせると、コードのネストが深くなるという問題があります。特にテーブル駆動テストでは、ループ・t.Runsynctest.Test の3段階のネストが生じます。
この問題は testing/synctest の導入以来多くの開発者が体験しており、x/net/http2x/net/internal/http3 など複数のパッケージで独自のヘルパー関数が実装されています。

提案された解決策

以下のシグネチャを持つ synctest.Subtest 関数を追加します。

func Subtest(t *testing.T, name string, f func(*testing.T)) {
    t.Helper()
    t.Run(name, func(t *testing.T) {
        t.Helper()
        Test(t, f)
    })
}

この関数は t.Run の内部で synctest.Test を呼ぶことと完全に等価であり、魔法的な動作は一切ありません。

これによって何ができるようになるか

t.Runsynctest.Test の組み合わせを1行に簡略化でき、テーブル駆動テストにおける過度なネストを解消できます。コードの可読性が向上し、コピー&ペーストミスによる「別のテスト関数を呼んでしまう」バグのリスクも低減されます。

コード例

// Before: 従来の書き方(t.Run + synctest.Test の組み合わせ)
for _, test := range []struct {
    name string
}{
    {name: "test 1"},
} {
    t.Run(test.name, func(t *testing.T) {
        synctest.Test(t, func(t *testing.T) {
            // テスト本体(ネストが深い)
        })
    })
}
// After: synctest.Subtest を使った書き方
for _, test := range []struct {
    name string
}{
    {name: "test 1"},
} {
    synctest.Subtest(t, test.name, func(t *testing.T) {
        // テスト本体(ネストが1段階浅くなる)
    })
}

議論のハイライト

  • 提案者の @neild 自身が「trivial(些細)な関数である一方、だからこそ標準ライブラリに入れる価値がある」という矛盾した立場を認めており、類似の synctest.Sleep(#77169、承認済み)の議論と同様の構図となっています。
  • 関連 Issue #77169(synctest.Sleep)のレビュー中に @nicholashusin が x/net の複数パッケージで同一のヘルパーが実装されている事実を指摘し、本提案の実用性を後押ししています。
  • @griesemer は「controversial ではないが、必要かどうかは不明」と述べており、標準ライブラリへの追加基準(「誰もが書くような些細なコードを提供する価値があるか」)を慎重に見極めている状況です。
  • 類似の synctest.Sleep は最終的に「テスト内ではほぼ必ずこのパターンを使う」という実績から承認されており、Subtest も同様の判断がなされる可能性があります。
  • 現在は「active」ステータスで議論継続中であり、まだ「likely accept」や「accepted」には至っていません。

関連リンク