目次
概要
単体テストにおいて、データベースや外部APIなどの「外部依存」を切り離し、テスト対象のロジックだけを検証するために使われるライブラリが「Moq(モック)」です。 Moqを使用すると、インターフェースを実装した「偽物のオブジェクト(Mock)」を簡単に作成し、そのメソッドが呼ばれたときの戻り値を自由に設定(Setup)できます。
仕様(入出力)
- インストール: NuGetパッケージ
Moqをプロジェクトに追加します。 - 入力: モック化したいインターフェースや抽象クラス
- 出力: その型を実装したMockオブジェクト
- 主なクラス:
Mock<T>
パッケージのインストール
dotnet add package Moq --version 4.14.3
基本の使い方
using Moq;
// 1. Mockオブジェクトの生成
// ICalculatorというインターフェースの偽物を作る
var mock = new Mock<ICalculator>();
// 2. 振る舞いの設定 (Setup)
// "Add(1, 2) が呼ばれたら 100 を返す" という嘘の動作を定義
mock.Setup(c => c.Add(1, 2)).Returns(100);
// 3. Mockオブジェクトの利用
// .Object プロパティで、ICalculatorの実体(偽物)を取得
ICalculator calculator = mock.Object;
// 実行結果は 100 になる
var result = calculator.Add(1, 2);
コード全文
実際にインターフェースを定義し、それをMoqで模倣して動かすコンソールアプリケーションの例です。
using System;
using Moq;
namespace MoqSample
{
class Program
{
static void Main()
{
Console.WriteLine("--- Moq Basic Usage ---");
// 1. Mockオブジェクトの生成
// 依存しているインターフェース(IMessageService)のモックを作成
var mockService = new Mock<IMessageService>();
// 2. メソッドの振る舞いを定義 (Setup)
// GetMessage() メソッドが呼ばれたら、必ず "Hello from Moq!" を返すように設定
mockService
.Setup(service => service.GetMessage())
.Returns("Hello from Moq!");
// 3. テスト対象クラスにMockオブジェクトを渡す
// mockService.Object が IMessageService の実装クラスとして振る舞う
var consumer = new MessageConsumer(mockService.Object);
// 4. 実行
// 内部で GetMessage() が呼ばれ、設定した戻り値が返ってくる
consumer.PrintMessage();
}
}
/// <summary>
/// モック化対象のインターフェース
/// 通常はDBアクセスやAPI通信などを行う部分
/// </summary>
public interface IMessageService
{
string GetMessage();
}
/// <summary>
/// テスト対象のクラス
/// 外部から IMessageService を注入(DI)してもらう設計
/// </summary>
public class MessageConsumer
{
private readonly IMessageService _service;
public MessageConsumer(IMessageService service)
{
_service = service;
}
public void PrintMessage()
{
var message = _service.GetMessage();
Console.WriteLine($"Consumer received: {message}");
}
}
}
カスタムポイント
- 引数による分岐:
Setup(x => x.Method(It.IsAny<int>()))のようにIt.IsAny<T>()を使うと、どんな引数が来てもマッチさせることができます。特定の引数の時だけ別の値を返す設定も可能です。 - プロパティの設定:
mock.SetupGet(x => x.Name).Returns("MockName");のようにプロパティのゲッターをモック化したり、SetupAllProperties()でプロパティの値を保持できるスタブとして動作させたりすることも可能です。
注意点
- インターフェース推奨: Moqは動的にプロキシクラスを生成する仕組みのため、基本的にはインターフェース(
interface)または抽象クラス(abstract class)をモック化します。通常のクラスをモック化する場合、メソッドがvirtualでないとオーバーライドできず、振る舞いを変えることができません。 - Objectプロパティ:
mock変数自体は「Mockの設定や検証を行うための管理オブジェクト」です。テスト対象に渡す「偽の実体」はmock.Objectプロパティから取得します。ここを混同しないように注意してください。
応用
呼び出しの検証 (Verify)
メソッドが正しく呼ばれたかどうかを確認する機能です。
// GetMessage() が「一度だけ」呼ばれたことを検証する
// 呼ばれていなければテストは失敗(例外発生)する
mockService.Verify(service => service.GetMessage(), Times.Once);
まとめ
Moqの利用は new Mock<T>() から始まります。これにより、本物のデータベースやWeb APIを用意することなく、意図した値を返す「都合の良い部品」を即座に作り出し、テスト対象クラスのロジック検証に集中することができます。
