Moq(モックライブラリー)を使ってみる。
2012年2月11日 コメントを残す
0.前置き
ASP.NET MVCの開発ではコンポーネントテスト(単体テスト、ユニットテスト)が大事です。
# いつでも大事ですけど…。
特にデータアクセスする部分のモックを簡単に作れると、開発の時に幸せになれます。
今回はMoqというモックライブラリーを紹介してみたいと思います。
1.Moqとは
Moqは、Mock-Youと読みます。モッキューですね。なんか若干呼びにくい笑
開発プロジェクトはGoogleCode上にホストされています。こちらです。
Moqは強い型付けでモックを作ることができるので、初心者(?)にも簡単に使い始めることができます。
実際のプロジェクトでも利用していますが、機能的に不足を感じたことはないです。
2.インストール
Moqはnuget経由でインストールできます。
簡単。nuget、素晴らしい。
3.実際に使ってみる
インストールができたので、さっそく使ってみます。
3-1.テスト対象のクラスを作成する
テスト対象のクラスは以下のようです。
ProductLogicが、ProductDaoを経由してDBにアクセスするっていう感じです。
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; } } }
つづいて、このProductLogicに対するテストを作成します。
3-2.戻り値があるメソッドのテストをする
最初はテスト対象のメソッドが戻り値を持つ場合です。
この場合はテスト対象の出力値をAssertすればOKです。
[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); }
3-3.戻り値がvoidのメソッドをテストする
テスト対象が戻り値を持たない場合は、検証をどのように行うか悩んでしまいます。
今回はテスト対象の処理の最後に呼ばれるInsertメソッドに着目し、Insertメソッドに渡された値を検証します。
ここではCallBackを利用し、入ってきた値を検証しています。
[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()); }
4.サンプルを書いてみての補足
CallBackで検証コードを入れる場合は、ちゃんとその検証コードが呼ばれたかチェックする必要があります。
もし呼ばれていなかったら、検証コードを作りこんだ意味がないですからね。
そういうわけで、dao.Verifyを使って、モックが何回呼ばれたかをチェックします。
5.サンプルコード
サンプルコードはgithubにホスティングしてあります。
AutoMapperのサンプル
コード本体
6.最後に
最近コンポーネントテストが楽しい。
いまはまだMoqしか試していないので、他のテストフレームワークも触ってみたいですね。
あとJavaScriptのテストフレームワークにも挑戦してみたいです。