NSubstitute チートシート

## NSubstitute とは

ユニットテストで利用することを想定した、.NET Framework 向けのMockライブラリ。
元となるインターフェースやクラスからテストで利用するためのモックオブジェクトを作成する。

公式サイト: http://nsubstitute.github.io/
利用バージョン: NSubstitute-1.4.3.0

## チートシート

### 生成

- interfaceからモック生成
`var calculator = Substitute.For<ICalculator>();`

- 実クラスからモック生成 (仮想メンバのみをモック化。それ以外は実際に実行される)
`var calculator = Substitute.For<CalculatorClass>();`


### 挙動を設定

- 戻り値設定
`calculator.Add(1, 1).ReturnsForAnyArgs(99);`

- 戻り値設定 (特定引数)
`calculator.Add(1, 2).Returns(3);`

- 処理呼び出し
`calculator.Add(1, 1).ReturnsForAnyArgs(x => Console.Log("called."));`

- 1回目は10, 2回目は20を返す
`calculator.Add(1, 1).ReturnsForAnyArgs(10, 20);`


### 呼び出し結果確認

以下を実行すると、確認結果が正しくなかったときにReceivedCallsExceptionが発生。

- 呼び出されたことを確認
`calculator.ReceivedWithAnyArgs().Add(1, 1);`

- 呼び出されたことを確認  (特定引数)
`calculator.Received().Add(1, 2);`

- 呼び出された回数確認
`calculator.ReceivedWithAnyArgs(3).Add(1, 1);`

- プロパティが呼び出されたことを確認
`var dummy = calculator.Received().prop;          // getter
calculator.Received().prop = "hoge"; // setter`

- 呼び出し状態クリア
`calculator.ClearReceivedCalls();`


## (付録) unityでの利用方法

以下URLからdllのバイナリを取得
https://github.com/nsubstitute/NSubstitute/downloads

(解凍フォルダ)\lib\NET35\NSubstitute.dll
……をunityの"Assets/Plugins"以下へコピー

エディタで NSubstitute.dll を選択し、ExcludePlatformsのEditor以外のチェックをONにしておく


以下のようなC#ファイルを作成してTestRunnerで実行

```C#
using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using NSubstitute;

public interface ISample {
    int Hoge();
}

public class NSubstituteTest {
    [Test]
    public void SubstituteTest() {
        var mockSample = Substitute.For<ISample>();
        mockSample.Hoge().Returns(99);

        Assert.AreEqual(99, mockSample.Hoge());
    }
}
```

## (付録) サンプルコード

```C#
using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using NSubstitute;

// モック作成元のインターフェース
public interface ISample {
    int Hoge();
    int Fuga(int n);
    int hogeProp { get; set; }
}

public class NSubstituteTest {
    // 挙動を設定
    [Test]
    public void Returns() {
        // モックの作成
        var mockSample = Substitute.For<ISample>();

        // 戻り値設定
        mockSample.Hoge().ReturnsForAnyArgs(99);
        Assert.AreEqual(99, mockSample.Hoge());

        // 戻り値設定 (特定引数)
        mockSample.Fuga(0).Returns(99);
        Assert.AreEqual(99, mockSample.Fuga(0));

        // 処理呼び出し
        mockSample.Fuga(2).Returns(n => { Debug.Log("called."); return 0; });
        mockSample.Fuga(2);

        // 1回目は10, 2回目は20を返す
        mockSample.Fuga(1).Returns(10, 20);
        Assert.AreEqual(10, mockSample.Fuga(1));
        Assert.AreEqual(20, mockSample.Fuga(1));
    }

    // 呼び出し結果確認
    [Test]
    public void Received() {
        // モックの作成
        var mockSample = Substitute.For<ISample>();

        // 呼び出されたことを確認
        mockSample.Hoge();
        mockSample.ReceivedWithAnyArgs().Hoge();

        // 呼び出されたことを確認  (特定引数)
        mockSample.Fuga(1);
        mockSample.Received().Fuga(1);
        mockSample.DidNotReceive().Fuga(2);

        // 呼び出された回数確認
        mockSample.ReceivedWithAnyArgs(1).Fuga(1);
        mockSample.Fuga(9);
        mockSample.Fuga(9);
        mockSample.ReceivedWithAnyArgs(3).Fuga(1);

        // プロパティが呼び出されたことを確認
        var dummy = mockSample.DidNotReceive().hogeProp;
        dummy = mockSample.hogeProp;
        dummy = mockSample.Received().hogeProp;

        mockSample.DidNotReceive().hogeProp = 1;
        mockSample.hogeProp = 1;
        mockSample.Received().hogeProp = 1;

        // 呼び出し状態クリア
        mockSample.ClearReceivedCalls();
        mockSample.Received(0).Hoge();
    }
}
```