【Moq】Moq.VerifySet()を用いたExcel描画のテスト方法


Moqとは

型さえあれば未実装であってもMock(=ダミーの実装)を作ってくれる。
実装の出来不出来に関係なくテストを書ける。

Excelに描画するテスト

今のデータをExcelに描画する機能をClosedXMLを用いて実装しているのですが、ちゃんと描画されたか否か確認するのが少し大変です。
例えばサーバー側にExcelがあることを前提としている場合はClosedXMLの正式な実装を使ったときにLinuxサーバーなどのExcelがない環境では正しく実行されない。
そのため、なるべく環境に依存しないコードを書きたい。

そこで今回はMoqでClosedXMLのダミーを作り、そのダミーを使って自ら書いたプログラムが正しい挙動か確認します。
Mocking library for .NET

描画された文字が正しいか判定すテスト

テストの流れは
1. テストしたいクラスの初期化
2. moqでClosedXMLのIF、実体クラスを生成
3. 生成したクラス・メンバーに値を入れた時の返り値を設定(ダミー実装)
4. 値を入れられることを確認(テスト)

とします。

//確認したいメソッド
//Renderの中では指定したsheetのrow,colに値を代入するだけとする
class Renderer()
{
    public void Render(sheet, row, col)
    {
        //例
        sheet.Cell(row, col).Value = "糖質過多";
    }
}

//テスト
public class Test()
{
    public void RenderTest()
    {
        //1. テストしたいクラスの初期化
        var renderer = new Renderer();

        //2. moqでClosedXMLのIF、実体クラスを生成
        //MoqでClosedXMLのラッパークラスを作る
        var mockSheet = new Mock<IXLSheet>();
        var mockeCell = new Mock<IXLCell>();
        //Mock<T>.Objectで型引数の実態クラスを生成する
        var mockSheetObject = mockSheet.Object;

        //3. 生成したクラス・メンバーに値を入れた時の返り値を設定
        //mockCell.Valueプロパティのsetterにstring型なら何でも代入できるようにする
        //Verifiable()でVerify()できるようにする
        mockCell.SetupSet(o => o.Value = It.IsAny<string>()).Verifiable();
        //Setup()で引数とそれに対する返り値を設定する
        mockSheetObject.Setup(o => o.Cell(1, 30)).Returns(() => mockCell.Object);

        //4. 値を入れられることを確認(テスト)
        //mockSheetObectに上で指定した引数を渡す
        renderer.Render(mockSheetObject, 1, 30);
        //mockCell.Valueプロパティに"糖質過多"が代入できることを確認する 
        mockCell.VerifySet(o => o.Value = "糖質過多");
    }
}

これでテストは完了です。
使用したMoqの関数を一つずつ見ていきましょう

Moqで使用した関数

Mock.Object

モックオブジェクトを取得する。指定した型の実装クラスを作ってくれます。

Mock.InitializeInstance()

Mock.Setup()

Setup()は「実装する関数を準備する」関数です。

Mock.SetupSet()

返り値がVoidSetupPhrase<T> : SetupPhraseとなりこのSetupPhraseクラス内に引数の値(今回であればIXLCell Cell(row, col)の返り値)を保持します。

WherePhrase.SetupSet()

Mock.SetupSet().Returns()

SetupSet()ではSetupPhraseクラスに値を保持させましたが、Returns()ではその値を保持していた場合にどんな値を返すか設定します。
今回は引数(row: 1, col:30)が入力されたときの返り値はmockCell.Objectであると定義しています。
mockCellはIXLCellIFのダミー実装ですね。

SetupPhrase.Verifiable()

It.IsAny()

T型のダミーな値を返します。用法としては指定した型を受け入れるようになります。
今回はstring型の値であればどんな値でも代入できるようにしました。

It.IsAny().Verifiable()

Verifiable()はSetupクラス内のプライベートなフラグをVerifyにします。
これによりテストでVerify()が使えるようになるようです。

フラグには他にOverridderMatchedがあるようですがこれらの使われ方は追いきれませんでした。。ご存じでしたら教えて下さい。
enum Flags

Setup.MarkAsVerifiable()

Mock.VerifySet()

ここまででSetterに値が代入されたかを判定する。代入されていなければ例外が投げられテストが通らない。
今回は実装クラス(Moqではない方)で”糖質過多”を代入しているのでテストパスとなる。

まとめ

Verify~の関数を使えばvoidの関数をテストできるので便利ですね。