📝

C#のモックライブラリ

2023/03/18に公開

Moqとは

単体試験コードを作成する上で、外部依存部分箇所などでI/Fの実装をしてくれたりするC#用のライブラリ
https://github.com/moq/moq4

外部依存しないようDIするようにしていた場合、単体試験作成時に対象のI/Fの実装を試験用に作成する必要がある
その際に依存処理をテスト用に置き換えて検証することができるライブラリ

通常

テスト用に想定値を返すダミーを作成しそれを指定
この場合だとIFが増えればその分実装が必要であったり、結果を変えたくなったときに条件分岐や別途作成する必要出る可能性がある

/// <summary>
/// ダミー使用
/// </summary>
[TestMethod()]
public void GetIFReturnTest()
{
    var instance = new TestTargetClass(new TestTargetIFStub());
    var ret = instance.GetIFReturn("Test1");

    Assert.AreEqual(false, ret);
}
/// <summary>
/// テスト用
/// </summary>
public class TestTargetIFStub : ITestTargetIF
{
    public bool IsEnable(string str)
    {
        if (str == "Test1")
            return false;
        return true;
    }
 
    public Task<bool> IsEnableAsync(Parameter param)
    {
        throw new NotImplementedException();
    }
}

moq使用

/// <summary>
/// Moq使用
/// </summary>
[TestMethod()]
public void GetIFReturnTest_Moq()
{
    var mock = new Mock<ITestTargetIF>();
    mock.Setup(x => x.IsEnable("Test1")) // 引数が指定文字列の場合のみ(引数を固定しない場合はIt.IsAnyを使用)
        .Returns(false);
    var instance = new TestTargetClass(mock.Object);
    var ret = instance.GetIFReturn("Test1");

    Assert.AreEqual(false, ret);
    // 呼び出されていることの検証
    mock.Verify(x => x.IsEnable("Test1"), Times.Once);
}

テスト対象

/// <summary>
/// テスト対象クラス
/// </summary>
public class TestTargetClass
{
    private ITestTargetIF _testInterface;
 
    /// <summary>
    /// コンストラクタ
    /// </summary>
    /// <param name="testTargetIF"></param>
    public TestTargetClass(ITestTargetIF testTargetIF) => _testInterface = testTargetIF;
 
    /// <summary>
    /// 外部依存
    /// </summary>
    /// <returns></returns>
    public bool GetIFReturn(string str)
    {
        return _testInterface.IsEnable(str);
    }
 
 
    /// <summary>
    /// 外部依存
    /// </summary>
    /// <returns></returns>
    public async Task<bool> GetIFReturnAsync(int val)
    {
        return await _testInterface.IsEnableAsync(new Parameter() { a = val });
    }
}
public interface ITestTargetIF
{
    // 外部に依存する処理を実施
    bool IsEnable(string str);
 
    Task<bool> IsEnableAsync(Parameter param);
}
 
public class Parameter
{
    public int a { get; set; } = 0;
}
public class TestTargetIFConcrete : ITestTargetIF
{
    public bool IsEnable(string str)
    {
        // 外部に依存する処理(外部通信など)
        return true;
    }
 
    public async Task<bool> IsEnableAsync(Parameter param)
    {
        await Task.Delay(0);
        return false;
    }
}

Discussion