ASP.NET MVCにおけるテスト
第1回でも解説したように、ASP.NET MVCの魅力の1つにテストの容易性・親和性という点が挙げられます。前回作成したサンプルアプリケーションに対して、テストプロジェクトを追加します。[ファイル]-[追加]-[新しいプロジェクト]を選択し、テストプロジェクトから[ASP.NET MVC Project Test Template]を選択しましょう。テストの作成手順はVSTSの単体テスト作成と変わりありません。
実際にサンプルを見てみましょう(図9~10)。
テストコードは以下のようになります。
[TestMethod] public void HelloTest() { // PubsControllerの準備 PubsController controller = new PubsController(); // 実行 ViewResult result = controller.Hello() as ViewResult; // 検証 ViewDataDictionary viewData = result.ViewData; Assert.AreEqual("Hello, MVC Framework!", viewData["Hello"]); }
同様に、URLルーティングに対しても簡単にテストが行えます(図11~12)。しかし、URLルーティングに対するテストでは、HttpContextを利用することになります。本来であれば、さまざまな準備が必要になりますが、サンプルでは擬似的なHttpContextを作成するために「moq」を利用します。moqは参照設定に加えるだけで簡単にモックオブジェクトを生成し利用できます。moqの魅力はいくつかありますが、テストを記述していてもモックテストを利用したことがない開発者をターゲットにしているためモックテストを少ない学習コストで簡単に利用できる点にあります(モックテストを利用したことがある方はより少ない学習コストで利用できます)。moqに関する詳細はリンク先を参照ください。
using System.Web; using System.Web.Routing; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; // <中略> [TestMethod] public void DefaultRoutTest() { RouteCollection routes = new RouteCollection(); MvcApplication.RegisterRoutes(routes); // 擬似HttpContextを利用してURLルートマッピングの設定 RouteData route = GetMockContext(routes,"~/Pubs/Details/BU1032"); // ルートマッピング検証 Assert.IsNotNull(route, "探してるルートは見つかりませんでした"); Assert.AreEqual("Pubs", route.Values["controller"], "Pubs コントローラーは存在しません"); Assert.AreEqual("Details", route.Values["action"], "Detailsアクションメソッドは存在しません。"); Assert.AreEqual("BU1032", route.Values["id"], "IDが違います。"); } // 疑似HttpRequestとHttpContextを生成 private RouteData GetMockContext(RouteCollection routes,string url) { var request = new Mock<HttpRequestBase>(); // パラメタのURLを相対パスとして設定 request.Setup( req => req.AppRelativeCurrentExecutionFilePath).Returns(url); var context = new Mock<HttpContextBase>(); // 疑似リクエストパスから疑似HttpContextを生成 context.Setup(ctx => ctx.Request).Returns(request.Object); // rdataをルートマッピングの設定として返す RouteData rdata = routes.GetRouteData(context.Object); return rdata; }
GetMockContextメソッドでは、ひとことで言ってしまうとHttpRequestBaseクラスと、HttpContextBaseクラスのモックオブジェクトを生成しています。
具体的に説明すると、それぞれのモックオブジェクトに対して、Setupメソッドを使いMock<T>で宣言された型のオブジェクトをセットアップします。セットアップに必要な情報はラムダ式で記述していきます。その結果をReturnsメソッドで、型を定めて返しています。上記コードでは、requestオブジェクトに、AppRelativeCurrentexecutionFilePathメソッドを使い、アプリケーション仮想パスを取得後、相対パスに変換します。相対パスはをパラメタとして渡されたURLを利用し、擬似的なリクエストを作成しています。
続いて、contextオブジェクトに生成したrequestオブジェクトを渡し、それを活用して擬似HttpContextを生成しています。
ルートに対するMockルートオブジェクト生成後は、通常のテストどおり、生成したMockルートオブジェクトに対してルートマッピングのテストを行っています。
ControllerクラスとURLルーティングに関するテストでは、従来のASP.NETと違い、実際にアプリケーションを実行しなくてもテストを実行できます。この点から、従来のASP.NETよりもテスト部分において優れていることがお分かりいただけるかと思います。
まとめ
今回はASP.NET MVCで実開発を行う際に利用が多くなるであろうフィルタ/AJAX/単体テストについて触れました。第1回~第3回までの内容をもとに、MSDNを参照しながら構築をすればある程度のWebアプリケーションが構築できるようになるかと思います。
次回は、ASP.NET MVCにおいて主流となり得るRepositoryパターンについて解説予定です。お楽しみに。