testing/synctest: add Subtest function
要約
概要
testing/synctestパッケージにSubtest関数を追加するproposalです。testing.T.Runとsynctest.Testを組み合わせた定型処理を一つの関数にまとめることで、テーブル駆動テストにおけるコードのネスト(字下げ)を削減します。
ステータス変更
active → likely_accept
2026年6月3日に開催されたProposal Review Meeting(@aclements、@griesemer、@neild ら参加)において、「likely accept」と判定されました。類似のsynctest.Sleep関数(issue #77169)が既にacceptedとなった前例があり、同様の「ユーザーが繰り返し書くヘルパー関数を公式に提供する」という方針と一致していることが評価されました。最終コメント待ちの状態です。
技術的背景
現状の問題点
testing/synctestパッケージでサブテストを書く際、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) {
// 実際のテストコード(三段階の字下げ)
})
})
}
x/net/http2やx/net/internal/http3など複数のパッケージで、同様のラッパー関数が独自に書かれていることが確認されており、これは共通ニーズの証左です。また、関数名のコピーペーストミス(TestBが誤ってtestAを呼ぶ等)も起こりやすいという指摘もあります。
提案された解決策
synctest.Subtest関数を追加します。実装は以下の通り、完全に自明なラッパーです。
// Subtest runs f in a bubble as a subtest of t called name.
//
// It is exactly equivalent to calling t.Run with a function that calls Test.
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の二重ネストを一行のsynctest.Subtest呼び出しに置き換えることができます。テーブル駆動テストで特に効果を発揮し、実際のテストロジックのインデントが一段階減ります。
コード例
// Before: t.Run + synctest.Test の二重ネスト
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
// テストコード(三段階の字下げ)
})
})
}
// After: synctest.Subtest で一段階削減
for _, test := range testCases {
synctest.Subtest(t, test.name, func(t *testing.T) {
// テストコード(二段階の字下げ)
})
}
議論のハイライト
- 「On the one hand, it's incredibly trivial. On the other hand, it's incredibly trivial.」 — 提案者の@neildは実装が自明であることを認めつつも、ほぼすべてのsynctest使用パッケージで同様のヘルパーを書いていると述べており、標準提供の正当性を訴えた。この表現は以前の
synctest.Sleep(#77169)の議論でも使われており、「自明だが有用」という共通のパターンとなっている。 - @griesemeの懸念: 「必ずしも必要かどうか不明」とコメントしており、標準ライブラリへの追加基準として、自分で書けるほど自明なコードを含めるべきかという疑問が提示された。
- 実績による正当性: x/netの複数箇所で同名の
synctestSubtestヘルパーが既に独立して実装されており(@nicholashusinが指摘)、これがエコシステム全体での共通ニーズを裏付ける根拠となった。 - #76607(syntactic overhead提案)との関連: より包括的な構文糖衣の提案(docコメントアノテーション等)は既に否定的に扱われており、今回の提案はその代替として現実的な小さな改善として位置付けられる。
t.Helper()の考慮: 提案のシグネチャにt.Helper()が含まれており、テスト失敗時のスタックトレースが正しく表示される設計になっている。