Moq.dll on ASP.NET MVC
昨日Moq.dllを使ってみたので、早速ASP.NET MVCに適用してみました。ここで、ControllerクラスのUserプロパティやら、HttpContextプロパティやらの設定はうまく行ったのですが、その他に色々問題があったのではまずはメモしてみる。
Moq.dllの適用先としては、わんくま同盟のデモ用に作った、以下のロジックコードに適用してみます。
[Authorize] [HandleError] public class BuyHistoryController : Controller { readonly IOrderRepository<Order> orderRepository; public BuyHistoryController() //: this(new OrderRepository()) { } public BuyHistoryController(IOrderRepository<Order> orderRepository) { this.orderRepository = orderRepository; } // // GET: /BuyHistory/ public ActionResult Index() { string username = User.Identity.Name; try { var model = orderRepository.GetByUsername(username).OrderByDescending(order => order.OrderDate); if (model == null || model.Count() == 0) { return RedirectToAction("Empty"); } else { return View(model); } } catch (Exception e) { Trace.WriteLine(e); return RedirectToAction("Sorry", "Result"); } } (中略) }
これに対するテストコードを以下で記述しました。
[TestMethod()] public void 購入してないユーザがEmptyビューに飛ぶTest01() { Type expected = typeof(RedirectToRouteResult); //ActionResult actual; //モック系の作成 var mockControllerContext = new Mock<ControllerContext>(); var mockHttpContextBase = new Mock<HttpContextBase>(); var mockIdentity = new Mock<IIdentity>(); var mockPrincipal = new Mock<IPrincipal>(); var mockBuyHistoryController = new Mock<BuyHistoryController>(new TestOrderRepository()); //ユーザ情報の設定 mockIdentity.Setup(identity => identity.IsAuthenticated).Returns(true); mockIdentity.Setup(identity => identity.Name).Returns("購入してないユーザ"); mockPrincipal.Setup(principal => principal.Identity).Returns(mockIdentity.Object); mockHttpContextBase.Setup(httpContextBase => httpContextBase.User) .Returns(mockPrincipal.Object); //コントローラにUserオブジェクト設定 //mockBuyHistoryController.Setup(buyHistoryController => buyHistoryController.User) // .Returns(mockPrincipal.Object); // ⇒これだとダメ、UserプロパティはhttpContext参照してたよ・・・orz //mockBuyHistoryController.Setup(buyHistoryController => buyHistoryController.HttpContext) // .Returns(mockHttpContextBase.Object); // ⇒これもダメ、HttpContextプロパティはControllerContext参照してたよ・・・orz mockControllerContext.Setup(controllerContext => controllerContext.HttpContext) .Returns(mockHttpContextBase.Object); //コントローラ生成 var controller = mockBuyHistoryController.Object; controller.ControllerContext = mockControllerContext.Object; //テスト実行 var actual = controller.Index(); //なぜか actual が null で帰ってくる・・・ Assert.AreEqual(expected, actual.GetType()); }
上のテストコードを作成した程度で以下にハマって見ました。
- 「やっべ、Mockインスタンスにコンストラクタが渡せない!」⇒実はnew Mock<>()でコンストラクタ渡せる。
- うっほ、Controller.Userプロパティが設定できない ⇒ Controller.csを見ると、普通にHttpContextプロパティ参照してる
- うっほ、Controller.HttpContextプロパティが設定できない ⇒ Controller.csを見ると、普通にControllerContextプロパティ参照してる
という流れを経た後、とりあえずController.User.Nameからユーザ名を持ってくるサンプルを記述完了。
と・こ・ろ・が、このテストコードなら「return RedirectToAction("Empty");」の結果が返ってくると思っているのでsが、なぜかnullが帰ってくる。しかも例外がおきてない。うーん、色々と考える必要が有るなぁ…。