テスト時に本物のオブジェクトの代わりに使う「替え玉」の総称。Gerard Meszaros が『xUnit Test Patterns』で 5 種類に体系化した。Stub・Mock・Spy・Fake・Dummy を用途で使い分ける。
概要
単体テスト では、対象を外部依存(DB・API・時刻・乱数)から切り離す必要がある。このとき本物の代わりに テストダブル を使う。「ダブル(double)」は映画の代役(スタントダブル)と同じ意味。
5 種類のテストダブル
| 種類 | 役割 | いつ使うか |
|---|---|---|
| Stub | 決め打ちの値を返すだけ | テスト対象が「読み取る」依存先 |
| Mock | 呼び出された事実を 検証する | テスト対象が「書き込む」依存先で、呼び出しの正しさを検証 |
| Spy | 呼び出しを記録するだけ(事後検証) | Mock より柔軟に、後から呼び出し履歴を確認 |
| Fake | 簡易実装(インメモリ DB 等) | 本物に近い振る舞いが必要、保守性重視 |
| Dummy | 引数を埋めるためだけ | 引数として渡す必要があるが、実際には使われない |
Stub の例
// テスト対象が getUser(123) を呼ぶ → 固定値を返す
const userStub = {
findById: (id) => ({ id: 123, name: "山田太郎" })
}
// テスト対象を実行
const result = orderService.createOrder(userStub, ...)
// 結果を検証(Stub 自体は検証しない)
expect(result.customerName).toBe("山田太郎")
Mock の例
// 「save が 1 回呼ばれた」ことを検証する
const orderRepoMock = jest.fn()
orderService.save(orderRepoMock, order)
// 呼び出された事実を検証
expect(orderRepoMock).toHaveBeenCalledWith(order)
expect(orderRepoMock).toHaveBeenCalledTimes(1)
Mock vs Spy の違い
| Mock | Spy |
|---|---|
| 期待値を 事前 に書く(厳格) | 呼び出しを記録、 事後 に検証(柔軟) |
| 期待外の呼び出しは即失敗 | テスト終了時に確認 |
| 振る舞いを強制 | 観察するだけ |
Fake が一番強い
| 観点 | Mock / Stub | Fake |
|---|---|---|
| 本物への忠実度 | 低(事前ハードコード) | 高(簡易実装で振る舞う) |
| API 変更への追従 | 全テスト書き直し | Fake 1 箇所修正で済む |
| AI 駆動開発との相性 | △ | ◎ |
リポジトリパターン で IOrderRepository を切り、 InMemoryOrderRepository を Fake として実装 すれば、DB 起動なしで業務ロジックを単体テストできる。AI ループが秒で回る理想形。
アンチパターン
| 失敗 | 起きること |
|---|---|
| Mock 一辺倒 | API 変更で全テストが壊れる、メンテ地獄 |
| Mock 過剰 | 「テストは通るが本物では壊れる」状態に |
| 全部 Fake | テスト対象 vs Fake で、本物のバグを検出できない |
| 内部実装に Spy を当てる | リファクタで全テスト壊れる、内部結合 |
指針: 境界(DB・外部 API)だけ Mock、内部は Fake、副作用検証は Spy、決め打ち入力は Stub。
AI 駆動開発との関係
AI に「テスト書いて」と指示すると、 モック一辺倒 で書きがち。次のように指示すると保守性が上がる:
テストダブルの方針:
- DB アクセスは InMemoryOrderRepository (Fake) を使う
- 外部 API は MSW でモック
- 副作用の検証は Spy で「呼ばれた事実」だけを確認
- 内部メソッドは Mock しない
関連記事
- 開発手法ガイド:テスト技法編 — テストダブル全体像
- 開発手法ガイド:TDD 編 — テストダブルで TDD を高速化
関連用語
- 単体テスト — テストダブルが最も使われるレベル
- 結合テスト — テストダブルの範囲を絞るレベル
- リポジトリパターン — Fake への差し替えで単体テスト高速化
- ヘキサゴナルアーキテクチャ — アダプタ差し替えでレイヤー別テスト
- SOLID 原則 — DIP(依存性逆転)がテストダブルを可能にする