ASP.NET Core MVC と xUnit.NET でユニットテストを行う Part.2

DIに対してユニットテストを考える

前回で、ユニットテストの最低限の環境を整えました。

mrgchr.hatenablog.com

今回は、以前に利用したDIに対してテストを書いてみます。

mrgchr.hatenablog.com

基本的な考え方

特別なことは必要なくて、コントローラーのコンストラクタやアクションに対して、依存オブジェクトを直接与えるだけです。
ですが、せっかくInterfaceを定義してあるので、下記のようなテスト用のダミークラスを導入します。

class DummyValueService : Services.IValueService
{
  public int GetValue()
  {
    return 42;
  }
}

それに伴ってテストは下記のようになります。

[Fact]
public void Test1()
{
  var service = new DummyValueService();
  var controller = new NiceController(service, service);
  var view = controller.Index(service) as ViewResult;
  var expected = 42;

  var actual1 = view.ViewData["constructorInject1"];
  var actual2 = view.ViewData["constructorInject2"];
  var actual3 = view.ViewData["actionInject"];

  Assert.Equal(expected, actual1);
  Assert.Equal(expected, actual2);
  Assert.Equal(expected, actual3);
}

このようにDIを導入したことでコントローラーのテストが容易に記述できるようになっています。

が!

こんなこと(ダミークラス作成)をいちいちやっていられないのです!

そんなことを避けるために、モックフレームワークを導入する

というわけで、モックフレームワークを導入します。
C#で人気のモックフレームワークと言えばMoqです。
ユニットテストフレームワークは色々人気を分けていますが、モックフレームワークではMoqが一番人気なのではないでしょうか。

github.com

準備

Moqですが、現時点では公式の.NET Core対応パッケージは用意されていないようです。
しかし.NET Core対応版のフォークがあるようなのでそれを利用します。
そのためにまずは以下のようにNugetFeedを追加します。

[Tools]-[Options]-[NuGet Package Manager]-[Package Sources]

f:id:mrgchr:20161108214920p:plain

右上の十字アイコンより以下を追加します。 Source : https://www.myget.org/F/aspnet-contrib/api/v3/index.json

Moqを追加する

テストプロジェクトのproject.jsonに下記を追加します。

"moq.netcore": "4.4.0-beta8",
"System.Diagnostics.TraceSource": "4.0.0"

私の環境では、System.Diagnostics.TraceSourceを追加しないとNotFoundExceptionが発生しました。

モックフレームワークを利用したテストを書く

で、Moqを利用したテストは下記のようになります。

[Fact]
public void Test1()
{
  var mock = new Moq.Mock<Services.IValueService>();
  mock.Setup(x => x.GetValue()).Returns(42);
  var controller = new NiceController(mock.Object, mock.Object);
  var view = controller.Index(mock.Object) as ViewResult;
  var expected = 42;

  var actual1 = view.ViewData["constructorInject1"];
  var actual2 = view.ViewData["constructorInject2"];
  var actual3 = view.ViewData["actionInject"];

  Assert.Equal(expected, actual1);
  Assert.Equal(expected, actual2);
  Assert.Equal(expected, actual3);
}

最初の例と比べてモックフレームワークの良いところは、例えばインタフェースの一部実装などができます。
ダミークラスを作成する場合はインタフェースのメソッドを全て実装する必要がありますが、モックフレームワークを利用すればテストに必要なメソッドのみをモック(物まね)させることができます。