導入
DB・外部API・時刻など「本物を使うとテストが遅い・不安定」な依存先を、偽物(モック)に差し替えるNuGetライブラリがMoqです。DIP(抽象への依存)が前提になります。
図解
flowchart LR
T["テスト対象"] --> I["インターフェース(抽象)"]
I -->|本番| R["本物(DB/API)"]
I -->|テスト| M["モック(Moqが生成)<br/>「こう返す」と指定"]
style M fill:#e8f5e9
サンプル
Moqの記法はこうです(ローカルでNuGetを入れて使います)。
// --- 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はこれを自動生成する道具です)。実務と同じく、抽象・本番用の実装・テスト用の偽物をそれぞれ別ファイルに置きます。
1. 抽象(IDiscount.cs)。差し替えの継ぎ目になるインターフェースです。
public interface IDiscount
{
double Rate();
}
2. テスト用の偽物(FakeDiscount.cs)。固定値を返すだけ。本来はテストプロジェクト側に置くファイルです。
// 手動モック(固定値を返す偽物)。Moqはこのクラスを自動生成してくれる
public class FakeDiscount : IDiscount
{
private readonly double _rate;
public FakeDiscount(double rate) => _rate = rate;
public double Rate() => _rate;
}
3. テスト対象(PriceCalculator.cs)。相手が本物か偽物かを知りません。だから差し替えられます。
public class PriceCalculator
{
private readonly IDiscount _discount;
public PriceCalculator(IDiscount discount) => _discount = discount;
public int Calculate(int price) => (int)(price * (1 - _discount.Rate()));
}
4. テスト(Program.cs)。偽物を注入すれば、DBもAPIも無しで一瞬で検証できます。
var calc = new PriceCalculator(new FakeDiscount(0.1));
Console.WriteLine(calc.Calculate(1000)); // 900
- 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です。