我的ASP.NET MVC应用程序中的菜单的URL是从控制器/操作生成的。所以,他们打电话给
controller.Url.Action(action, controller)
现在,我如何在单元测试中完成这项工作? 我使用
成功使用MVCContribvar controller = new TestControllerBuilder().CreateController<OrdersController>();
但无论我尝试用它做什么,我都会得到controller.Url.Action(action,controller)因NullReferenceException而失败,因为Url == null。
更新:它不是关于如何拦截HttpContext。我通过几种方式做到了这一点,使用MVCContrib,Scott Hanselman的假装示例,以及来自http://stephenwalther.com/blog/archive/2008/07/01/asp-net-mvc-tip-12-faking-the-controller-context.aspx的那个。这对我没有帮助,因为我需要知道假的值是什么......是ApplicationPath吗?我该如何设置?是否需要匹配被调用的控制器/动作?也就是说,Url.Action如何工作以及如何满足它?
另外,我知道我可以做IUrlActionAbstraction并继续使用它...但我不确定我是否想这样做。毕竟,我有MVCContrib / Mock全功率,为什么我需要另一个抽象。
答案 0 :(得分:21)
以下是使用MvcContrib的TestControllerBuilder模拟UrlHelper的方法:
var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
HomeController controller = CreateController<HomeController>();
controller.HttpContext.Response
.Stub(x => x.ApplyAppPathModifier("/Home/About"))
.Return("/Home/About");
controller.Url = new UrlHelper(
new RequestContext(
controller.HttpContext, new RouteData()
),
routes
);
var url = controller.Url.Action("About", "Home");
Assert.IsFalse(string.IsNullOrEmpty(url));
答案 1 :(得分:4)
如果您使用的是Moq
(而不是MvcContrib
的{{1}}),则可以模拟上下文,类似于@ DarianDimitrov的回答:
TestControllerBuilder
这不会设置var controller = new OrdersController();
var context = new Mock<System.Web.HttpContextBase>().Object;
controller.Url = new UrlHelper(
new RequestContext(context, new RouteData()),
new RouteCollection()
);
属性,但它允许controller.HttpContext
执行(并返回一个空字符串 - 不需要模拟)。
答案 2 :(得分:3)
假装很简单:
var fakeUrlHelper = A.Fake<UrlHelper>();
controller.Url = fakeUrlHelper;
A.CallTo(() => fakeUrlHelper.Action(A<string>.Ignored, A<string>.Ignored))
.Returns("/Action/Controller");
答案 3 :(得分:0)
这是使用NSubstitute解决问题的另一种方法。希望对别人有帮助。
// _accountController is the controller that we try to test
var urlHelper = Substitute.For<UrlHelper>();
urlHelper.Action(Arg.Any<string>(), Arg.Any<object>()).Returns("/test_Controller/test_action");
var context = Substitute.For<HttpContextBase>();
_accountController.Url = urlHelper;
_accountController.ControllerContext = new ControllerContext(context, new RouteData(), _accountController);