本文へスキップ
BecomeCoder

C#デザインパターンコース · 第2章 TDD ― テスト駆動開発 · レッスン17

Moq ― モックで依存を差し替える

ブラウザで完結

導入

DB・外部API・時刻など「本物を使うとテストが遅い・不安定」な依存先を、偽物(モック)に差し替えるNuGetライブラリがMoqです。DIP(抽象への依存)が前提になります。

図解

flowchart LR
    T["テスト対象"] --> I["インターフェース(抽象)"]
    I -->|本番| R["本物(DB/API)"]
    I -->|テスト| M["モック(Moqが生成)<br/>「こう返す」と指定"]
    style M fill:#e8f5e9

サンプル

// --- Moq の記法(読み物) ---
// var mock = new Mock<IDiscountService>();
// mock.Setup(s => s.GetRate("VIP")).Returns(0.1m);   // 振る舞いを指定
// var calc = new PriceCalculator(mock.Object);
// Assert.Equal(900m, calc.Calculate("VIP", 1000m));
// mock.Verify(s => s.GetRate("VIP"), Times.Once());   // 呼ばれたか検証

// ブラウザでは「手動フェイク」で同じ考え方を再現(Moqはこれを自動生成する道具)
var calc = new PriceCalculator(new FakeDiscount(0.1));
Console.WriteLine(calc.Calculate(1000));   // 900

interface IDiscount { double Rate(); }
class FakeDiscount : IDiscount            // 手動モック(固定値を返す偽物)
{
    private readonly double _rate;
    public FakeDiscount(double rate) => _rate = rate;
    public double Rate() => _rate;
}
class PriceCalculator
{
    private readonly IDiscount _discount;
    public PriceCalculator(IDiscount discount) => _discount = discount;
    public int Calculate(int price) => (int)(price * (1 - _discount.Rate()));
}
  • Moqはnew Mock<IXxx>()で偽物を作り、Setup(...).Returns(...)で振る舞いを指定する
  • Verify(...)で「その呼び出しが行われたか」も検証できる
  • 本質は「インターフェースの手動実装(フェイク)を自動生成してくれる道具」

演習

var greeter = new Greeter(new FakeClock(2026));
Console.WriteLine(greeter.Greet());   // あけましておめでとう

// TODO: IClock(Year()→int)を実装する FakeClock を定義してください(固定の年を返す)
interface IClock { int Year(); }
class Greeter
{
    private readonly IClock _clock;
    public Greeter(IClock clock) => _clock = clock;
    public string Greet() => _clock.Year() == 2026 ? "あけましておめでとう" : "こんにちは";
}
___
  • 期待される出力: あけましておめでとう
ヒント1を見る

class FakeClock : IClock { private readonly int _y; public FakeClock(int y) => _y = y; public int Year() => _y; }

ヒント2を見る

固定値を返す偽物を注入すると、時刻に依存せずテストできます

まとめ

  • Moqは依存先を偽物(モック)に差し替えるライブラリ
  • Setupで振る舞い指定、Verifyで呼び出し検証
  • 仕組みは素のC#の手動フェイクと同じ(DIが前提)

次回: 読みやすい検証を書くFluentAssertionsです。

実際に動かしてみよう

本文のサンプルや演習のコードは、コードブロック右上の「コピー」ボタンでコピーして、下のエディタに貼り付ければそのまま実行できます。

C# — ブラウザ内で実行

ブラウザ内でC#を動かす環境を読み込みます(初回のみ数秒)。
スクロールして表示された時点でも自動で読み込まれます。