QUnitとReSharper

0.前置き

ASP.NET MVCでのビューを開発する際や、Win8のメトロスタイルアプリを開発する際において、
JavaScriptの重要性がどんどん高まっています。
今までなんとなしに逃げてきたJavaScriptですが、本格的に取り組まなくてはいけません。
今回はそんなJavaScriptの開発におけるコンポーネントテストの方法をまとめておこうと思います。
普段仕事でReSharperを使っているので、ReSharper+QUnitの組み合わせでのテスト方法を簡単にまとめます。

1.それぞれのツールの紹介

QUnitとは
QUnitはもともとjQuery開発のために作成されたテスティングフレームワークです。
いまやjQueryへの依存がないため、JavaScriptのテスト一般に利用可能です。
ドキュメントは、こちらにあります。

ReSharper
ReSharperはVisualStudioのアドオンです。
開発生産性向上ツール?とでも言うのでしょうか。
コーディング支援、リファクタリング支援、コンポーネントテスト支援などなど多くの機能を搭載しています。
開発している会社は、JetBrainsで最新バージョンは6.1です。
詳しい情報は、こちらからどうぞ。

2.インストール

※ReSharperのインストールの話は省きます。
ReSharper(Ver.6以降)が入っていれば、QUnitのインストール作業は不要です。
ReSharperがビルドされた際には最新のQUnitが組み込まれているようです。
設定も特にないです。オプションにQUnitのテスト結果を表示するブラウザーを設定するぐらいです。

3.実際に使ってみる

3-1.テスト対象のJSファイルを作成する

calculate.jsとして、以下のコードを作成しました。

function add(x,y) {
    return x + y;
}

function substract(x,y) {
    return x - y;
}

function muliply(x,y) {
    return x * y;
}

3-2.テストを行うJSファイルを作成する

test/calculate.test.jsとして以下のコードを作成しました。

//↓ReSharperにテスト対象のコードを教えてあげます。
/// <reference path="../calculate.js"/>

//↓個々のテストメソッドをグループ化します。(QUnitの構文)
module("Calculator tests");

test("SumTest", function() {
    var result = add(2, 3);
    equals(5, result, "Sum of 2 and 3 is 5");
});

test("SubstractTest", function() {
    var result = substract(5, 1);
    equals(4, result, "Substracting 1 from 5 gives 4");
});

3-3.テストを実行する

*1. テストを実行する*
テストモジュールや、テストメソッドの左にテスト実行マーク(ReSharperの機能)が出るので
これを選択して実行します。

*2.Visual Studio上でテスト結果を確認する*
Visual Studio上で結果は確認できます。

*3.QUnitの標準の方法でテスト結果を確認する*
もちろんQUnit標準の方法で結果を確認することができます。

4.サンプルを書いてみての補足

QUnitの標準の方法ですと、テスト結果を表示するHTMファイルを作成する必要があります。
しかし、ReSharperを用いる場合は必要ないです。ReSharperがテスト実行時に勝手に作ってくれます。

5.サンプルコード

サンプルコードはgithubにホスティングしてあります。
QUnitのサンプル
テストコード本体

6.最後に

MsTestと同じ手法でコンポーネントテストを実施できるのは魅力的ですね。

Moq(モックライブラリー)を使ってみる。

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のテストフレームワークにも挑戦してみたいです。