概要
TDDにおいて「モック」は、
外部依存や副作用を分離し、純粋な設計を支える道具として強力に機能する。
しかし一方で、過剰なモックはテストを壊れやすく、設計を不自然にする。
本稿では、C# + xUnit + Moq による実装例を通じて、
**「モックを使うべきとき」「使ってはいけないとき」**の判断基準と、設計への影響を明確にしていく。
1. モックの目的は「外部依存の隔離」
テスト対象を純粋なロジックに保つには、外部との通信(DB/API/メール/時間など)を排除する必要がある。
public interface IClock {
DateTime Now { get; }
}
public class GreetingService {
private readonly IClock _clock;
public GreetingService(IClock clock) {
_clock = clock;
}
public string Greet() {
return _clock.Now.Hour < 12 ? "Good morning" : "Good evening";
}
}
✅ 時間に依存せず、コアロジックのテストが可能な設計
2. Moqでのモック作成とTDDでの利用
public class GreetingServiceTest {
[Fact]
public void Greet_BeforeNoon_ReturnsGoodMorning() {
var clock = new Mock<IClock>();
clock.Setup(c => c.Now).Returns(new DateTime(2024, 4, 2, 9, 0, 0));
var service = new GreetingService(clock.Object);
var result = service.Greet();
Assert.Equal("Good morning", result);
}
}
- ✅ モックは「対象が依存している振る舞い」の予測可能な置換である
- ✅ 「結果が時間に依存しない」という仕様の検証が可能になる
3. モックを使うべきタイミング
タイミング | 理由 |
---|---|
外部I/Oが関わる | 実行速度・安定性・副作用防止 |
状態や出力が予測しにくい | 時間・乱数・非同期など |
フローを確認したい(コールされたか) | verify系を使って振る舞いを検証したい時 |
契約に従っているか検証したい | interfaceの利用側の正しさを担保 |
4. モックを使ってはいけない場面
状況 | なぜNGか |
---|---|
単純なデータ構造だけの依存 | モックよりフェイクや直接生成の方が自然 |
テスト対象の内部実装に依存する | 実装の詳細に依存しすぎてテストが脆くなる |
コール順、回数などを過剰に縛る | 振る舞いを固定化し、リファクタに弱くなる |
「なんでもモック」でテストを書く | テストが信頼できるドキュメントでなくなる |
5. モックとスタブ・フェイクの選定戦略
手法 | 用途 | 特徴 |
---|---|---|
モック | コールされたことを検証 |
Verify() で振る舞いを確認 |
スタブ | 特定の戻り値を返す | 振る舞いのシミュレーション |
フェイク | 簡易実装で依存を代替 | 実装あり。シンプルなテストDBなど |
選定基準は「どの設計レイヤを検証したいか」
設計判断フロー
① テスト対象が外部に依存しているか? → YES → モック/スタブを検討
② 検証したいのは戻り値か?呼び出しか? → 値 = スタブ、呼び出し = モック
③ 依存のインターフェースがあるか? → NO → 設計見直し(DIへ)
④ モックを導入することでテストが壊れやすくならないか? → YES → 他の手段を検討
よくあるミスと対策
❌ あらゆる依存に対して機械的にモックを適用
→ ✅ **テストの目的が曖昧になる。**構造と責務を見直すべきシグナル
❌ モックの戻り値や呼び出し順にテストが過剰に依存
→ ✅ 振る舞いを過度に縛ると設計が変えられなくなる
❌ モックが肥大化してメンテ不能に
→ ✅ フェイクや実装差し替え可能な構造を優先する
結語
モックはTDDの中で最も誤用されやすい道具だ。
しかし本質的には、**“テストの正確性を保ちつつ、構造の透明性を確保するための隔離戦略”**である。
- 依存を分離することで、テストは高速・安定・意図的になる
- 過剰なモックは、テストを壊れやすくし、設計を硬直させる
- モックは「使うこと」が目的ではない。「構造を制御する」ためにある
TDDとは、
“正しい隔離によって、誤差を制御し、構造を純化するための戦略的な設計運用である。”