コンテンツにスキップ

Goのtestingパッケージ内部を読み解く

概要

Go 標準ライブラリの testing パッケージのソースコードを読み込んで解説したリポジトリ。テストの仕組みを内部から理解できる。

GitHub: https://github.com/sivchari/dive-into-testing-package

詳細

testing パッケージを読み解くことで以下の知識が得られる:

testing パッケージの主要な構造

// T はテスト関数の基本構造
type T struct {
    common
    isParallel bool
    isEnvSet   bool
    context    *testContext
}

// common はT/B/Fの共通フィールド
type common struct {
    mu          sync.RWMutex  // テスト状態の保護
    output      []byte        // t.Log の出力バッファ
    w           io.Writer
    ran         bool
    failed      bool
    skipped     bool
    done        bool
    // ...
}

t.Parallel() の仕組み

func (t *T) Parallel() {
    // 親テストに「並列実行可能」を通知
    // バリアで全並列テストが揃うまで待機
    // その後一斉に実行
}

内部では sync.WaitGroup とチャネルを使って並列テストの同期を制御している。

t.Cleanup() の仕組み

func (t *common) Cleanup(f func()) {
    t.cleanupName = callerName(0)
    t.cleanups = append(t.cleanups, f)
}
// テスト終了後にスタック順(LIFO)で実行

サブテスト (t.Run) の実装

func (t *T) Run(name string, f func(t *T)) bool {
    // 新しい T を作成して goroutine で実行
    // 親 T の done チャネルで完了を待機
}

なぜ重要か / いつ使うか

  • テストが遅い原因の特定: t.Parallel() の内部動作を知ることでボトルネックがわかる
  • フレームワーク作成: testing.T をラップするヘルパーライブラリを書く際に必須の知識
  • デバッグ力向上: テストが予期せず失敗・スキップされる理由を内部から追える
  • Go の標準ライブラリの読み方: testing パッケージはコード量が適度で Go の慣用パターンが詰まっており、標準ライブラリ読解の入門として最適