ルーティングのテスト

Mockクラスを使用してルーティングの単体テストを行う。

モックライブラリ

http://code.google.com/p/moq/

使い方は、配布ページドキュメントと、ここを参考にした。

モックオブジェクトの作成
通常の実装とは異なり、Aメソッド呼び出しのときにBパラメータを渡された場合はCを返す。のような感じで動きを登録していく。
(必要な動きだけをMockクラスメソッドを使用して登録していく感じ。)
//こんな感じで

interface IEvenOdd
{
    //偶数か
    bool IsEven(int val);
    //奇数か
    bool IsOdd(int val);
}

static class EvenOddFactory
{
    static IEvenOdd Create()
    {
        var mock = new Mock<IEvenOdd>();

        //テストでは1から5までの値だけしか使用されないので、
        //必要な動きだけ定義する。

        //偶数
        mock.Setup(eo => eo.IsEven(2)).Returns(true);
        mock.Setup(eo => eo.IsEven(4)).Returns(true);
        //奇数
        mock.Setup(eo => eo.IsOdd(1)).Returns(true);
        mock.Setup(eo => eo.IsOdd(3)).Returns(true);
        mock.Setup(eo => eo.IsOdd(5)).Returns(true);

        return mock.Object;
    }
}

テスト用のHttpContextBase派生クラス

モックライブラリを使ってHttpContextBase派生クラスを生成する。
ここを参考に作成。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Moq;

namespace SimpleBBS2
{
	public static class MockHttpContextFactory
	{
	    public static HttpContextBase Create(string url)
	    {
	        var hcb_mock = new Mock<HttpContextBase>();
	        var req_mock = new Mock<HttpRequestBase>();

	        req_mock.Setup(req => req.AppRelativeCurrentExecutionFilePath).Returns("~/" + url);
	        hcb_mock.Setup(hcb => hcb.Request).Returns(req_mock.Object);

	        return hcb_mock.Object;
	    }
	}
}

ルーティングテスト

こんな感じ。
テスト対象のHttpApplication派生クラスを使ってRegisterRoutesするのを忘れないように。

※検索ページのようなパラメーター付きのテストで、コントローラー名にパラメーターも含まれてしまう。
これはどうにか対処してテストできるようにしないと、、、、
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using NUnit.Framework;
using Moq;


namespace SimpleBBS2Test
{
    [TestFixture]
    public class RouteTest
    {
        private abstract class PageTest
        {
            protected RouteCollection rc;

            protected PageTest(RouteCollection rc)
            {
                this.rc = rc;
            }

            public abstract void Test();
        }


        private class CreateTest : PageTest
        {
            public CreateTest(RouteCollection rc) : base(rc)
            {
            }

            public override void Test()
            {
                {
                    var hc = MockHttpContextFactory.Create("SimpleBBS2/Thread/Create");
                    var rd = rc.GetRouteData(hc);
                    Assert.AreEqual("SimpleBBS2", rd.Values["controller"]);
                    Assert.AreEqual("CreateThread", rd.Values["action"]);
                }

                {
                    var hc = MockHttpContextFactory.Create("SimpleBBS2/CreateThread");
                    var rd = rc.GetRouteData(hc);
                    Assert.AreEqual("SimpleBBS2", rd.Values["controller"]);
                    Assert.AreEqual("CreateThread", rd.Values["action"]);
                }
            }
        }

        private class ThreadListTest : PageTest
        {
            public ThreadListTest(RouteCollection rc)
                : base(rc)
            {
            }

            public override void Test()
            {
                {
                    var hc = MockHttpContextFactory.Create("SimpleBBS2/ThreadList");
                    var rd = rc.GetRouteData(hc);
                    Assert.AreEqual("SimpleBBS2", rd.Values["controller"]);
                    Assert.AreEqual("ThreadList", rd.Values["action"]);
                }
            }
        }
        
        private class SearchTest : PageTest
        {
            public SearchTest(RouteCollection rc)
                : base(rc)
            {
            }

            public override void Test()
            {
                {
                    var hc = MockHttpContextFactory.Create("SimpleBBS2/Search");
                    var rd = rc.GetRouteData(hc);
                    Assert.AreEqual("SimpleBBS2", rd.Values["controller"]);
                    Assert.AreEqual("Search", rd.Values["action"]);
                    Assert.AreEqual(null, rd.Values["t"]);
                    Assert.AreEqual(null, rd.Values["p"]);
                }

                //↓クエリ文字列付きだと、アクション名にクエリ文字列が含まれてしまう。
                
                //{
                //    var hc = MockHttpContextFactory.Create("SimpleBBS2/Search?t=タグ");
                //    var rd = rc.GetRouteData(hc);
                //    Assert.AreEqual("SimpleBBS2", rd.Values["controller"]);
                //    Assert.AreEqual("Search", rd.Values["action"]);
                //    Assert.AreEqual("タグ", rd.Values["t"]);
                //    Assert.AreEqual(null, rd.Values["pageno"]);
                //}
                //
                //{
                //    var hc = MockHttpContextFactory.Create("SimpleBBS2/Search?t=タグ&pageno=1");
                //    var rd = rc.GetRouteData(hc);
                //    Assert.AreEqual("SimpleBBS2", rd.Values["controller"]);
                //    Assert.AreEqual("Search", rd.Values["action"]);
                //    Assert.AreEqual("タグ", rd.Values["t"]);
                //    Assert.AreEqual("1", rd.Values["pageno"]);
                //}
            }
        }

        [Test]
        public void DoTest()
        {
            var rc = new RouteCollection();
            SimpleBBS2.MvcApplication.RegisterRoutes(rc);

            var tests = new List<PageTest>();
            tests.Add(new CreateTest(rc));
            tests.Add(new ThreadListTest(rc));
            tests.Add(new SearchTest(rc));

            foreach (var test in tests)
                test.Test();
        }
    }
}