第33章:モックフレームワーク入門(最小だけ)🧪
(テーマ:**「外部通知(メール送信)をモック化して、呼ばれたことをテストする」**📣✅)
今日のゴール🎯💖

この章が終わったら、あなたはこんなことができるようになります😊✨
-
「外部に何かする(通知する/保存する)」みたいな副作用を、テストで安全に確認できる📣✅
-
モックフレームワークで最低限の
- 戻り値(/Task)を用意する
- 呼び出し回数を確認する をサクッと使えるようになる🧪✨
-
そして一番大事:モックの使いすぎを避ける基準が持てる🎭🚫🍰
0) どれを使う?(2026年1月の“今”ベース)🔍✨
この章では Moq をメインで扱います(いちばん情報も例も多いから💡)。
この章の狙いは「Moqを極める」じゃなくて、**“必要な時だけ最小で使える”**ようになることだよ〜😊🪄
1) モックフレームワークって何?🍩🎭
ざっくり言うと…
「本物の代わりのオブジェクト(テストダブル)」を、簡単に作る道具です🧰✨
特に便利なのはここ👇
- 外部通知(メール/Slack/Push)
- 外部I/O(HTTP/DB/ファイル)
- 時間・乱数 など、テストで扱いづらいもの⏰🎲
そして、この章で覚える“最小セット”はこれだけ👇
- Setup:呼ばれたらこう返してね(TaskでもOK)🧪
- Verify:ちゃんと呼ばれた?何回?✅
2) 使いどころのルール(ここ超大事)📌💖
モックは便利だけど、使いすぎるとテストがつらくなる😵💫💦 なので判断基準を決めよ〜!
✅ モックを使っていい典型
- 「通知した/しない」が仕様📣✅
- 「保存した/しない」「送信した/しない」みたいに 副作用が目的のとき
🚫 モックを避けたい典型
- 計算ロジックや純粋な判定(戻り値で確認できるやつ) → それは 値のAssert で十分😇✨
迷ったら:「それ、結果(値)で確認できない?」って自分に聞くのがコツだよ😊🧠✨
3) ハンズオン:メール送信をモック化する📧🧪✨
題材(超ミニ)🧸
「購入が成功したら、確認メールを送る」📧
- 成功 → SendAsyncが1回呼ばれる
- 失敗 → 呼ばれない
3-1) パッケージ追加(VSでもCLIでもOK)📦✨
CLI派なら(テストプロジェクトで)👇
dotnet add package Moq
(MoqはNuGetで配布されてるよ (nuget.org))
4) まず“テストから”書く(Red)🚦🔴
4-1) 依存(メール送信)をインターフェースにする📮
public interface IEmailSender
{
Task SendAsync(string to, string subject, string body);
}
4-2) テスト:成功したらメール送信される📧✅
using Moq;
using Xunit;
public class PurchaseServiceTests
{
[Fact]
public async Task Purchase_success_sends_confirmation_email()
{
// Arrange
var emailMock = new Mock<IEmailSender>();
// Taskを返すメソッドは、最低限ここを用意すると安心😊
emailMock
.Setup(x => x.SendAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns(Task.CompletedTask);
var sut = new PurchaseService(emailMock.Object);
// Act
await sut.PurchaseAsync(userEmail: "alice@example.com", amount: 1200);
// Assert(呼ばれたことを確認する!)
emailMock.Verify(
x => x.SendAsync(
"alice@example.com",
It.Is<string>(s => s.Contains("購入", StringComparison.Ordinal)),
It.IsAny<string>()),
Times.Once);
}
}
ポイント解説🧁✨
Setup(...).Returns(Task.CompletedTask):「呼ばれても落ちない」安全装置Verify(..., Times.Once):**「1回だけ送れ」**を仕様として固定📌It.Is<string>(...):件名がそれっぽいかだけ見る(細かすぎない)😊👌
5) 実装を書く(Green)🚦🟢
public class PurchaseService
{
private readonly IEmailSender _email;
public PurchaseService(IEmailSender email)
{
_email = email;
}
public async Task PurchaseAsync(string userEmail, int amount)
{
// ここでは「成功したことにする」ミニ実装でOK😊
// (第19章の仮実装の感覚!🩹)
await _email.SendAsync(
userEmail,
subject: "購入の確認",
body: $"ご購入ありがとうございます!金額: {amount}");
}
}
これでテストが通るはず🎉✨
6) もう1本テスト:失敗時は送らない(次のRed)🚦🔴➡️🟢
「失敗」を仕様にしたいので、テストで固定しよ〜💪😊
[Fact]
public async Task Purchase_failure_does_not_send_email()
{
// Arrange
var emailMock = new Mock<IEmailSender>();
emailMock
.Setup(x => x.SendAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns(Task.CompletedTask);
var sut = new PurchaseService(emailMock.Object);
// Act
await sut.PurchaseAsync(userEmail: "alice@example.com", amount: 0);
// Assert
emailMock.Verify(
x => x.SendAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()),
Times.Never);
}
ここで実装を少しだけ育てる🌱✨
public async Task PurchaseAsync(string userEmail, int amount)
{
if (amount <= 0)
return; // 失敗扱い(ミニ)
await _email.SendAsync(
userEmail,
subject: "購入の確認",
body: $"ご購入ありがとうございます!金額: {amount}");
}
7) よくあるハマりどころ集😵💫🧯
- ✅ Verifyが細かすぎる(本文が完全一致!とか) → 変更に弱くなるので、重要な部分だけ見るのがコツ😊
- ✅ モックだらけになって、テストが「手順の写し」になる → 「結果でAssertできるなら、結果で!」に戻る🧠✨
- ✅ asyncメソッドで
Setupしなくて挙動が分かりづらい → まずはReturns(Task.CompletedTask)を癖にしよ👍✨
8) AIの使い方(この章の勝ちパターン)🤖🪄
AIは“叩き台”に便利だよ〜😊✨(採用はテストが通ったものだけ✅)
おすすめプロンプト例👇
- 「このインターフェースをMoqでモックして、1回呼ばれたことをVerifyするテストを書いて」🤖
- 「Verifyが細かすぎないように、壊れにくいAssert/Verifyの粒度を提案して」🧠
- 「この副作用、モックで見るべき観点(回数/引数/呼ばない条件)を列挙して」📣✅
9) ミニ課題(コミット単位で)🎒✨
課題A:通知条件を増やす🎟️
-
amount >= 5000のときだけ「VIPありがとうメール」にする💌✨- テスト:件名に “VIP” が入ること(完全一致じゃなくてOK)
課題B:送信先が空なら送らない🚫📧
-
userEmailが空/空白なら送らない- テスト:
Times.Neverで固定
- テスト:
まとめ🎀✨
- モックフレームワークは 副作用(通知/保存/送信)を仕様として固定するのに強い📣✅
- この章は Setup(返す)+Verify(呼ばれた?) の最小だけでOK🧪✨
- モックは便利だけど、結果でAssertできるならそっち優先が平和😊🌸
次の章(第34章)は、この流れをそのまま使って 「呼ぶ/呼ばないが条件で変わる副作用」を、もっと仕様っぽくテストしていくよ〜📣✅✨