ASP.NET MVC:Mock controller.Url.Action

时间:2009-09-02 13:11:49

标签: asp.net-mvc

我的ASP.NET MVC应用程序中的菜单的URL是从控制器/操作生成的。所以,他们打电话给

controller.Url.Action(action, controller)

现在,我如何在单元测试中完成这项工作? 我使用

成功使用MVCContrib
var 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全功率,为什么我需要另一个抽象。

4 个答案:

答案 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);