0.前置き
ASP.NET MVCの開発ではコンポーネントテスト(単体テスト、ユニットテスト)が大事です。
# いつでも大事ですけど…。
特にデータアクセスする部分のモックを簡単に作れると、開発の時に幸せになれます。
今回はMoqというモックライブラリーを紹介してみたいと思います。
1.Moqとは
Moqは、Mock-Youと読みます。モッキューですね。なんか若干呼びにくい笑
開発プロジェクトはGoogleCode上にホストされています。こちらです。
Moqは強い型付けでモックを作ることができるので、初心者(?)にも簡単に使い始めることができます。
実際のプロジェクトでも利用していますが、機能的に不足を感じたことはないです。
2.インストール
Moqはnuget経由でインストールできます。
簡単。nuget、素晴らしい。
3.実際に使ってみる
インストールができたので、さっそく使ってみます。
3-1.テスト対象のクラスを作成する
テスト対象のクラスは以下のようです。
ProductLogicが、ProductDaoを経由してDBにアクセスするっていう感じです。
[sourcecode language=”csharp”]
namespace MoqSample
{
/// <summary>
/// テスト対象のクラス
/// </summary>
public class ProductLogic
{
public IProductDao ProductDao { get; set; }
public decimal CalculateTax(int id)
{
var domain = ProductDao.GetItemById(id);
var result = domain.Price * 0.05m;
return result;
}
public void EditProduct(Product item)
{
var id = item.Id;
var domain = ProductDao.GetItemById(id);
domain.Price *= 1.05m;
ProductDao.Insert(domain);
}
}
/// <summary>
/// モックで置き換える予定のDaoのインターフェイス
/// </summary>
public interface IProductDao
{
void Update(Product product);
void Insert(Product product);
Product GetItemById(int id);
List<Product> GetAllItems();
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
[/sourcecode]
つづいて、このProductLogicに対するテストを作成します。
3-2.戻り値があるメソッドのテストをする
最初はテスト対象のメソッドが戻り値を持つ場合です。
この場合はテスト対象の出力値をAssertすればOKです。
[sourcecode language=”csharp”]
[TestMethod]
public void CalculateTaxTest()
{
//Arrange
var dao = new Mock<IProductDao>();
dao.Setup(m => m.GetItemById(1))
.Returns(new Product
{
Id = 1,
Name = "Book",
Price = 300
});
var target = new ProductLogic { ProductDao = dao.Object };
//Act
var result = target.CalculateTax(1);
//Assert
Assert.AreEqual(15, result);
}
[/sourcecode]
3-3.戻り値がvoidのメソッドをテストする
テスト対象が戻り値を持たない場合は、検証をどのように行うか悩んでしまいます。
今回はテスト対象の処理の最後に呼ばれるInsertメソッドに着目し、Insertメソッドに渡された値を検証します。
ここではCallBackを利用し、入ってきた値を検証しています。
[sourcecode language=”csharp”]
[TestMethod]
public void EditProductTest()
{
//Arrange
//DBアクセス部分をモックで作成
var dao = new Mock<IProductDao>();
dao.Setup(m => m.GetItemById(10))
.Returns(new Product
{
Id = 10,
Name = "Book",
Price = 300
});
dao.Setup(m => m.Insert(It.IsAny<Product>()))
.Callback<Product>(p =>
{
//コールバックにてAssertを実行
Assert.AreEqual(10, p.Id);
Assert.AreEqual("Book", p.Name);
Assert.AreEqual(315, p.Price);
});
var target = new ProductLogic { ProductDao = dao.Object };
//Act
target.EditProduct(new Product { Id = 10 });
//Assert(一部)
dao.Verify(m => m.Insert(It.IsAny<Product>()), Times.Once());
dao.Verify(m => m.Update(It.IsAny<Product>()), Times.Never());
}
[/sourcecode]
4.サンプルを書いてみての補足
CallBackで検証コードを入れる場合は、ちゃんとその検証コードが呼ばれたかチェックする必要があります。
もし呼ばれていなかったら、検証コードを作りこんだ意味がないですからね。
そういうわけで、dao.Verifyを使って、モックが何回呼ばれたかをチェックします。
5.サンプルコード
サンプルコードはgithubにホスティングしてあります。
AutoMapperのサンプル
コード本体
6.最後に
最近コンポーネントテストが楽しい。
いまはまだMoqしか試していないので、他のテストフレームワークも触ってみたいですね。
あとJavaScriptのテストフレームワークにも挑戦してみたいです。
コメント