TESTING長文・約 137,055

ロンドン派 vs デトロイト派:単体テスト2大流派の思想と使い分け

ロンドン派 vs デトロイト派:単体テスト2大流派の思想と使い分け

「モックはどこまで使うべき?」その議論の裏には、単体テストの考え方が根本的に異なる2つの流派がある。Martin Fowlerの「Mocks Aren't Stubs」とKhorikovの『単体テストの考え方/使い方』を基に、ロンドン派とデトロイト派の歴史・思想・使い分けを事実ベースで整理します。

この記事のポイント

  • 単体テストには ロンドン派(Mockist)デトロイト派(Classicist) という 2 つの流派がある
  • 両派の違いは「単体テストにおける "単体" の定義」に起因する
  • ロンドン派:単体 = クラス、依存をすべてモック化し 振る舞い(相互作用) を検証 / デトロイト派:単体 = 振る舞いの単位、本物のオブジェクトを使い 状態(結果) を検証
  • どちらが正しいかではなく、プロジェクトの特性に応じて使い分けるのが現実的(Outside-In TDD と Inside-Out TDD の選択にも対応)

この記事の対象読者

  • テストは書いているが、モックの使い方に迷いがある方
  • 「テストが壊れやすい」と感じているが、原因が分からない方
  • テスト設計の背景にある思想を理解したい方

はじめに

「モックを使いすぎるとテストが壊れやすくなる」

「でもモックなしだとテストが遅くなるし、セットアップが大変」

この論争は、開発者コミュニティで繰り返されてきました。Stack OverflowやRedditで検索すれば、同じような議論が何年も続いていることに気づくでしょう。

実はこの対立の背景には、テストの考え方そのものが異なる「2つの流派」が存在します。

それがロンドン派(London School / Mockist)デトロイト派(Detroit School / Classicist)です。

両派は「単体テスト」という同じ言葉を使いながら、その定義が異なります。だから話が噛み合わない。これが、モック論争が終わらない根本的な理由です。

この記事では、Martin Fowlerの「Mocks Aren't Stubs」(2004年初版、2007年改訂)とVladimir Khorikovの『単体テストの考え方/使い方』(原著2020年)を主な参照元として、両派の歴史的背景・思想・トレードオフを事実ベースで整理します。

なお、テストで使う「モック」「スタブ」などの用語には正確な分類があります。これらの違いについては以下の記事で詳しく解説しています。

テストダブル完全ガイド:Vitest + React Testing Libraryでの実践

テストダブル完全ガイド:Vitest + React Testing Libraryでの実践

Martin Fowlerのテストダブル分類を基に、Vitest + React Testing Libraryでの実装パターンを解説。vi.fn()、vi.spyOn()、vi.mock()の使い分けとベストプラクティスを紹介します。

2つの流派の歴史的背景

デトロイト派(古典派)の起源

デトロイト派の源流は、Kent Beckにあります。

Beckは1996年にChrysler社の給与計算システム「C3(Chrysler Comprehensive Compensation System)プロジェクト」に参加し、エクストリーム・プログラミング(XP)の実践としてテスト駆動開発(TDD)を確立しました。C3プロジェクトの拠点がデトロイト(ミシガン州)だったことが、「デトロイト派」の名前の由来です(出典:Mocks Aren't Stubs - Martin Fowler)。XPの全体像(価値・プラクティスの体系)については以下の記事で詳しく解説しています。

エクストリーム・プログラミング(XP)入門|初版→第2版で何が変わったのか

エクストリーム・プログラミング(XP)入門|初版→第2版で何が変わったのか

TDDやペアプロの源流であるエクストリーム・プログラミング(XP)。Kent Beckの原著をもとに、初版(1999年)の4つの価値・12のプラクティスから第2版(2004年)での再構成まで、XPの全体像と思想的変遷を事実ベースで解説します。

2002年に出版された『テスト駆動開発』(原著:Test-Driven Development: By Example)で、BeckはTDDの基本的なアプローチを体系化しました。そのアプローチの特徴は以下の通りです。

  • 本物のオブジェクトをできるだけ使う
  • テストダブル(代役)は、使うのが困難な場合(外部API、データベースなど)にのみ使用する
  • テストは結果の状態を検証する

Martin Fowlerは「Mocks Aren't Stubs」の中で、古典派のスタイルをこう説明しています。

The classical TDD style is to use real objects if possible and a double if it's awkward to use the real thing. (古典的なTDDスタイルは、可能な限り本物のオブジェクトを使い、本物を使うのが厄介な場合にだけダブルを使うものである。)

ロンドン派(モック派)の起源

ロンドン派のルーツは、2000年代初頭のロンドンにあります。

2000年、Tim Mackinnon、Steve Freeman、Philip Craigの3人は、XP2000カンファレンスで「Endo-Testing: Unit Testing with Mock Objects」と題した論文を発表しました。これが「モックオブジェクト」という概念を世に広めた最初期の文献です。

彼らはロンドンのコンテクスチュアル広告会社Connextraで働いており、XPの実践の中でモックオブジェクトの手法を開発しました(出典:A Brief History of Mock Objects)。その後、この考え方はロンドンのExtreme Tuesday Club(XTC)(毎週火曜日に集まるXP実践者のコミュニティ)を通じて広まりました。

このアプローチは、Steve FreemanNat Pryceによって2009年の著書『Growing Object-Oriented Software, Guided by Tests』(通称GOOS)で体系化されました。

ロンドン派の特徴は以下の通りです。

  • テスト対象以外の依存をすべてモックに置換する
  • テストはオブジェクト間の相互作用(メソッド呼び出し)を検証する
  • Outside-Inのアプローチで、外側のインターフェースから内側へ向かって設計する

命名の由来

Martin Fowlerは「Mocks Aren't Stubs」の中で、この2つの呼び名について触れています。

  • デトロイト派:XPがC3プロジェクト(デトロイト)で生まれたことに由来
  • ロンドン派:モック手法がロンドンのXPコミュニティで発展したことに由来

「古典派(Classical / Classicist)」と「モック派(Mockist)」という呼び方も広く使われています。

「単体テスト」の定義が違う: 両派の根本的な分岐点

2つの流派の核心的な違い

両派の違いは、突き詰めると「単体テストにおける"単体"とは何か?」という定義の違いに帰着します。

Vladimir Khorikovは『単体テストの考え方/使い方』の中で、この違いを3つの観点から整理しています。

1. 「単体」の定義

ロンドン派 デトロイト派
単体の単位 1つのクラス 1つの振る舞い(複数クラスにまたがることもある)

ロンドン派にとって、「単体テスト」とは1つのクラスをテストすることです。そのクラスが依存する他のクラスはすべてモックに置換します。

デトロイト派にとって、「単体テスト」とは1つの振る舞い(ユースケース)をテストすることです。その振る舞いの実現に複数のクラスが関わっていても構いません。

2. 「隔離」の意味

ロンドン派 デトロイト派
何を隔離するか テスト対象を依存から隔離 テストケース同士を隔離

ロンドン派は「テスト対象のクラスを、その依存から隔離する」ことを重視します。だからすべての依存をモックに置換します。

デトロイト派は「テストケース同士が互いに影響しないこと」を重視します。共有状態(データベースなど)を持つ依存はモックに置換しますが、それ以外の依存は本物を使います。

3. 依存の扱い

Khorikovは依存を「共有依存(shared dependency)」と「プライベート依存(private dependency)」に分類し、各派がどう扱うかを整理しています。

依存の種類 ロンドン派 デトロイト派
共有依存(テスト間で状態を共有) データベース、ファイルシステム モック モック
プライベート依存(可変) 内部で生成されるオブジェクト モック 本物を使用
プライベート依存(不変) 値オブジェクト、定数 本物を使用 本物を使用

最大の違いは「プライベートな可変依存」の扱いです。ロンドン派はこれもモックに置換しますが、デトロイト派は本物を使います。

テスト設計の違い: 状態検証 vs 振る舞い検証

状態検証 vs 振る舞い検証

Martin Fowlerが「Mocks Aren't Stubs」で指摘したもう1つの重要な違いが、検証方法です。

状態検証(State Verification): デトロイト派の基本

状態検証は、テスト対象の操作を実行した後、結果の状態を確認するアプローチです。

[準備] → [実行] → [結果を確認]
// デトロイト派のスタイル(状態検証)
it('注文に商品を追加できる', () => {
  const warehouse = new Warehouse();
  warehouse.add('りんご', 50);
 
  const order = new Order('りんご', 10);
  order.fill(warehouse);
 
  // 状態を検証:注文が満たされたか? 在庫は減ったか?
  expect(order.isFilled()).toBe(true);
  expect(warehouse.getInventory('りんご')).toBe(40);
});

このテストは、OrderWarehouse内部実装がどう変わっても、振る舞いが正しければパスし続けます

振る舞い検証(Behavior Verification): ロンドン派の基本

振る舞い検証は、テスト対象が依存オブジェクトに対して正しいメソッド呼び出しを行ったかを確認するアプローチです。

[準備] → [実行] → [正しく呼び出されたか確認]
// ロンドン派のスタイル(振る舞い検証)
it('注文に商品を追加できる', () => {
  const mockWarehouse = {
    hasInventory: vi.fn().mockReturnValue(true),
    remove: vi.fn(),
  };
 
  const order = new Order('りんご', 10);
  order.fill(mockWarehouse);
 
  // 振る舞いを検証:正しいメソッドが正しい引数で呼ばれたか?
  expect(mockWarehouse.hasInventory).toHaveBeenCalledWith('りんご', 10);
  expect(mockWarehouse.remove).toHaveBeenCalledWith('りんご', 10);
});

このテストは、OrderWarehouseどのようにコミュニケーションするかを検証しています。

どちらが優れているか?

Fowlerは「Mocks Aren't Stubs」の中で、自身の立場を明言しています。

I've always been a old fashioned classic TDDer and thus far I don't see any reason to change. (私はずっと昔ながらの古典派TDDerであり、いまのところ変える理由は見当たらない。)

ただし、Fowlerはモック派のアプローチに価値がないとは言っていません。優れた開発者がモック派のスタイルで成功していることも認めた上で、自分の好みを述べています。

TDDスタイルの違い: Inside-Out vs Outside-In

Outside-In vs Inside-Out TDD

両派はTDD(テスト駆動開発)の進め方も異なります。

Inside-Out(デトロイト派)

デトロイト派のTDDは、内側のドメインロジックから外側へ向かって構築していきます。

1. ドメインモデル(最も内側)のテストを書く
2. ドメインモデルを実装する
3. それを使うサービス層のテストを書く
4. サービス層を実装する(本物のドメインモデルを使う)
5. さらに外側(API層など)へ進む

このアプローチでは、すでに動く内側のコードを土台にして、外側を構築します。

Outside-In(ロンドン派)

ロンドン派のTDDは、外側のインターフェースから内側へ向かって構築していきます。Freeman/Pryceの『Growing Object-Oriented Software, Guided by Tests』で詳述されたアプローチです。

1. ユーザーに最も近い層(UIやAPI)のテストを書く
2. 内側の依存はモックにして、まず外側を実装する
3. モックにした依存の実装に進む
4. さらに内側へ向かって実装する

このアプローチでは、ユーザーの要求から出発して、必要なインターフェースを発見していきます。Freeman/Pryceはこれを「テストに導かれた設計」と呼んでいます。

比較

Inside-Out(デトロイト派) Outside-In(ロンドン派)
出発点 ドメインモデル ユーザーインターフェース
設計の発見 内側から自然に浮かび上がる 外側からの要求で決まる
モックの役割 外部依存の代替 未実装の依存のプレースホルダー
利点 過剰設計を避けやすい ユーザー要求との整合性が高い
注意点 外側の設計が後回しになりがち モック定義が設計を制約することがある

それぞれのメリット・デメリット

Fowlerの分析とKhorikovの整理を基に、両派のトレードオフを整理します。

ロンドン派のメリット

1. テスト失敗時にバグの場所が特定しやすい

すべての依存をモックに置換しているため、テストが失敗すれば、原因はそのクラス自身のコードにあると断定できます。デトロイト派では、本物の依存を使うため、依存先のバグでテストが連鎖的に失敗することがあります。

2. テストのセットアップがシンプルになる場合がある

依存関係が深いオブジェクトでも、モックなら簡単にセットアップできます。

3. オブジェクト間のインターフェース設計を促進する

依存をモックに置換するために、必然的にインターフェースを意識した設計になります。Freeman/Pryceはこれを「ロールインターフェース」と呼び、ロンドン派の重要な利点としています。

ロンドン派のデメリット

1. 実装詳細への結合

モックは「どのメソッドが、どの引数で呼ばれるか」を検証します。これは内部実装への結合を意味し、リファクタリング時にテストが壊れやすくなります。

Khorikovはこの点を強く批判しています。彼は、モックで検証すべきなのは「外部から観測可能な振る舞い(外部APIへのリクエストなど)」に限られると主張します。内部のオブジェクト間のやり取りをモックで検証すると、テストがリファクタリングの妨げになると述べています。

2. 偽陽性のリスク

すべてをモックに置換すると、オブジェクト間の統合が実際に機能するかどうかは検証されません。テストは通るのに、本番環境では動かないという「偽陽性」のリスクがあります。

デトロイト派のメリット

1. リファクタリング耐性が高い

本物のオブジェクトを使い、結果の状態を検証するため、内部実装を変更してもテストは壊れにくいです。これはテストの長期的な保守性を高めます。

2. 統合レベルのバグを検出できる

複数のオブジェクトが実際に連携するため、オブジェクト間のインターフェースの不整合などを検出できます。

3. テストコードが仕様書として機能しやすい

「何を実行したら、何が起きるか」を状態で検証するため、テストコードが振る舞いの仕様書として読みやすくなります。

デトロイト派のデメリット

1. テスト失敗時の原因特定に時間がかかる場合がある

本物の依存を使うため、依存先のバグでテストが連鎖的に失敗し、原因の特定に手間取ることがあります。

2. セットアップが複雑になる場合がある

依存関係が深い場合、テストのセットアップに多くのオブジェクト生成が必要になることがあります。

どう使い分けるか: プロジェクト特性に応じた選択基準

「どちらが正解か」という議論には、明確な答えがありません。Khorikovは古典派を基本として推奨しつつも、ロンドン派が有効な場面があることも認めています。ここでは、プロジェクトの特性に応じた選択基準を提示します。

デトロイト派が向いているケース

  • ドメインロジックが複雑なプロジェクト(金融、会計、業務システムなど)
  • 長期的に保守するコードベース(リファクタリング耐性が重要)
  • テストを仕様書として活用したいチーム
  • ドメインモデルが確立していて、Inside-Outで設計しやすいケース

ロンドン派が向いているケース

  • 外部依存が多いプロジェクト(多数のAPIと連携するシステムなど)
  • インターフェース設計を洗練させたいフェーズ
  • アーキテクチャの境界を明確にしたいケース(ヘキサゴナルアーキテクチャなど)
  • Outside-Inでユーザー要求から設計を駆動したいケース

実務上の現実的なアプローチ

多くの現場では、両派の考え方を状況に応じて組み合わせるのが現実的です。

テスト対象 推奨アプローチ 理由
ドメインロジック デトロイト派(状態検証) リファクタリング耐性が重要
外部API・メール送信 ロンドン派(モック+振る舞い検証) 副作用の検証が必要
UIコンポーネント デトロイト派寄り(ユーザー視点で状態検証) 実装詳細への依存を避ける
アーキテクチャ境界 ロンドン派(インターフェース検証) 契約の遵守を検証

筆者の見解:プロジェクトのフェーズで使い分ける

筆者は、プロジェクトの成熟度に応じて流派を切り替えるアプローチを実践しています。

初期段階(ゼロからのスクラッチ開発)ではデトロイト派を採用します。開発初期はコードの変更が激しく、インターフェースも頻繁に変わります。この段階でロンドン派を使うと、インターフェース変更のたびにモック定義の更新が必要になり、テストのメンテナンスコストが跳ね上がります。デトロイト派であれば、本物のオブジェクトを使って結果の状態を検証するので、内部構造が変わってもテストは壊れにくいです。

コードが安定してきたフェーズではロンドン派を取り入れます。インターフェースが固まった段階でモックに切り替えると、テストの実行速度が上がり、テスト対象の責務も明確になります。安定したインターフェースに対するモック定義は変更頻度が低いため、メンテナンスコストも抑えられます。

この「デトロイト派から始めて、安定したらロンドン派を取り入れる」というアプローチは、両派のメリットをプロジェクトのライフサイクルに合わせて活用するものです。

テスト戦略全体の設計(単体テスト・結合テスト・E2Eテストの配分)については、以下の記事で詳しく解説しています。

テストピラミッド vs テスティングトロフィー: モダンフロントエンドのテスト戦略ガイド

テストピラミッド vs テスティングトロフィー: モダンフロントエンドのテスト戦略ガイド

「どのテストをどれくらい書くべき?」その悩みを解決。テストピラミッドとテスティングトロフィーの違いを理解し、React/TypeScript/Next.jsプロジェクトに最適なテスト戦略を実例付きで解説します。

まとめ

ロンドン派とデトロイト派の違いは、つまるところ「単体テストにおける"単体"をどう定義するか」の違いです。

ロンドン派(Mockist) デトロイト派(Classicist)
単体の定義 1つのクラス 1つの振る舞い
隔離の対象 テスト対象 ↔ 依存 テストケース ↔ テストケース
検証方法 振る舞い検証 状態検証
TDDスタイル Outside-In Inside-Out
代表的な文献 Freeman/Pryce『GOOS』 Beck『テスト駆動開発』

「どちらを選ぶべきか」よりも重要なのは、自分のプロジェクトでなぜそのアプローチを採るのかを説明できることです。モックを多用するなら、それが意図的な設計判断であるべきです。本物のオブジェクトを使うなら、リファクタリング耐性を重視しているという判断があるべきです。

どちらの流派にも、優れた実践者と、数十年の実績があります。大事なのは教条的にならず、プロジェクトの特性に応じて適切な手法を選ぶことです。

参考文献

SHARE
鶴田 篤広
ABOUT THE AUTHOR
鶴田 篤広
ソフトウェアエンジニア · クレインテック株式会社
CRANE TECH — TECHNICAL ADVISORY

テスト戦略の導入・改善でお困りですか?

テストの自動化から品質基盤の構築まで、御社のプロダクトに最適なテスト戦略をご提案します。