Moqを使用してC#での単体テストを容易にする方法

データベースやファイルファイルシステムなどの外部リソースにアクセスするコードの単体テストを作成する必要があることがよくあります。そのようなリソースが利用できない場合、テストを確実に実行できるようにする唯一の方法は、モックオブジェクトを作成することです。本質的に、これらの基礎となる依存関係の偽の実装を利用することで、テスト対象のメソッドとその依存関係の間の相互作用をテストできます。.Net開発者に最も人気のあるモックフレームワークの3つは、Rhino Mocks、Moq、およびNMockです。

これらの中で、Moqは最も柔軟で使いやすいかもしれません。Moqフレームワークは、モックをセットアップ、テスト、検証するためのエレガントな方法を提供します。この記事では、Moqと、それを使用してコードのユニットを依存関係から分離する方法について説明します。

Moqを使い始める

Moqを使用して、実際のオブジェクトをシミュレートまたは模倣するモックオブジェクトを作成できます。Moqは、クラスとインターフェイスの両方をモックするために使用できます。ただし、注意が必要な制限がいくつかあります。モックされるクラスは静的または封印することはできず、モックされるメソッドは仮想としてマークする必要があります。(これらの制限には回避策があることに注意してください。たとえば、アダプターのデザインパターンを利用して、静的メソッドをモックすることができます。)

Moqを使用する最初のステップは、単体テストプロジェクトで使用できるようにインストールすることです。GitHubからMoqをダウンロードし、必要に応じて参照を追加できます。ただし、参照を見逃す可能性が低く、簡単であるため、NuGetを介してMoqをインストールすることをお勧めします。NuGetコマンドラインで次のコマンドを使用してMoqをインストールできます。

Install-Package Moq

Moqを使用してインターフェースをモックする方法

インターフェイスをモックすることから始めましょう。Mockクラスを使用してモックオブジェクトを作成するための構文を以下に示します。

モックmockObjectType = new Mock();

ここで、IAuthorという名前の次のインターフェイスについて考えてみます。

パブリックインターフェイスIAuthor

    {{

        int Id {get; セットする; }

        string FirstName {get; セットする; }

        string LastName {get; セットする; }

    }

Moqフレームワークを使用すると、モックオブジェクトを作成し、プロパティ値を設定し、パラメーターを指定し、メソッド呼び出しで値を返すことができます。次のコードスニペットは、Moqを使用してIAuthorインターフェイスからインスタンスを作成する方法を示しています。

var mock = new Mock();

MockクラスはMoqフレームワークに属し、作成するインターフェイスのタイプを受け入れる汎用コンストラクターが含まれていることに注意してください。Moqは、ラムダ式、デリゲート、ジェネリックを利用します。これらすべてにより、フレームワークの使用が非常に直感的になります。

次のコードスニペットは、IAuthorインターフェイスをモックし、モックされたインスタンスのプロパティに適切な値を提供する方法を示しています。アサーションを使用して、モックされたインスタンスのプロパティの値を検証する方法に注意してください。

var author = new Mock();

author.SetupGet(p => p.Id).Returns(1);

author.SetupGet(p => p.FirstName).Returns(“ Joydip”);

author.SetupGet(p => p.LastName).Returns(“ Kanjilal”);

Assert.AreEqual( "Joydip"、author.Object.FirstName);

Assert.AreEqual( "Kanjilal"、author.Object.LastName);

Moqを使用してメソッドをモックする方法

次に、Articleという名前の次のクラスについて考えてみましょう。Articleクラスには、GetPublicationDateというメソッドが1つだけ含まれています。このメソッドは、記事IDをパラメーターとして受け取り、記事の公開日を返します。

パブリッククラスの記事

    {{

        public virtual DateTime GetPublicationDate(int articleId)

        {{

            新しいNotImplementedException();をスローします。

        }

    }

GetPublicationDateメソッドはArticleクラスにまだ実装されていないため、以下のコードスニペットに示すように、メソッドは現在の日付を公開日として返すようにモックされています。

var mockObj = new Mock();
mockObj.Setup(x => x.GetPublicationDate(It.IsAny()))。Returns((int x)=> DateTime.Now);

Setupメソッドは、パラメーターとして渡されるメソッドの動作を定義するために使用されます。この例では、GetPublicationDateメソッドの動作を定義するために使用されます。toの呼び出しIt.IsAny()は、GetPublicationDateメソッドが整数型のパラメーターを受け入れることを意味します。It静的クラスを参照します。Returnsメソッドは、Setupメソッド呼び出しで指定されたメソッドの戻り値を指定するために使用されます。この例では、Returnsメソッドを使用して、メソッドの戻り値を現在のシステム日付として指定しています。

Moqを使用すると、特定のメソッドまたはプロパティが呼び出されたかどうかを確認できます。次のコードスニペットはこれを示しています。

mockObj.Verify(t => t.GetPublicationDate(It.IsAny()));

ここでは、Verifyメソッドを使用して、モックオブジェクトでGetPublicationDateが呼び出されたかどうかを判断しています。

Moqを使用して基本クラスのメソッドをモックする方法

次のコードについて考えてみます。ここには、RepositoryBaseクラスとそれを拡張するAuthorRepositoryクラスの2つのクラスがあります。

パブリック抽象クラスRepositoryBase

{{

    public virtual bool IsServiceConnectionValid()

    {{

        //いくつかのコード

    }

}

パブリッククラスAuthorRepository:RepositoryBase

{{

    public void Save()

    {{

        if(IsServiceConnectionValid())

        {{

            //いくつかのコード

        }

    }

}

ここで、データベース接続が有効かどうかを確認するとします。ただし、IsServiceConnectionValidメソッド内のすべてのコードをテストしたくない場合があります。たとえば、IsServiceConnectionValidメソッドには、サードパーティライブラリに関連するコードが含まれている場合があります。私たちはそれをテストしたくないでしょう?ここで、MoqのCallBaseメソッドが役に立ちます。 

このような状況で、モックされた型でオーバーライドされた基本クラスのメソッドがあり、オーバーライドされたメソッドの基本バージョンのみをモックする必要がある場合は、CallBaseを利用できます。次のコードスニペットは、CallBaseプロパティをtrueに設定することにより、AuthorRepositoryクラスの部分的なモックオブジェクトを作成する方法を示しています。

var mockObj = new Mock(){CallBase = true};

mockObj.Setup(x => x.IsServiceConnectionValid())。Returns(true);

Moqフレームワークを使用すると、必要な機能だけで、テスト用のクラスとインターフェイスの動作を模倣するモックオブジェクトを簡単に作成できます。モックを使用したテストの詳細については、MartinFowlerによるこのすばらしい記事をご覧ください。