ASP.NET MVC:Mock controller.Url.Action

que*_*en3 23 asp.net-mvc

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

controller.Url.Action(action, controller)
Run Code Online (Sandbox Code Playgroud)

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

var controller = new TestControllerBuilder().CreateController<OrdersController>();
Run Code Online (Sandbox Code Playgroud)

但是无论我尝试用它做什么,我都会得到controller.Url.Action(动作,控制器)失败并且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全功率,为什么我需要另一个抽象.

Dar*_*rov 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));
Run Code Online (Sandbox Code Playgroud)

  • Tyler:RegisterRoutes是一个约定,使用MvcApplication.RouteTable.Routes.Add(...) (2认同)

Bob*_*tor 20

更简洁的方法是使用Moq(或任何其他您喜欢的框架)来模拟UrlHelper本身

var controller = new OrdersController();
var Mock<UrlHelper> UrlHelperMock = new Mock<UrlHelper>();

controller.Url = UrlHelperMock.Object;

UrlHelperMock.Setup(x => x.Action("Action", "Controller", new {parem = "test"})).Returns("testUrl");

var url = controller.Url.Action("Action", "Controller", new {parem = "test"});
assert.areEqual("/Controller/Action/?parem=test",url);
Run Code Online (Sandbox Code Playgroud)

干净简单.


ash*_*999 5

如果您正在使用Moq(而不是MvcContrib's TestControllerBuilder),您可以模拟上下文,类似于@DarianDimitrov 的回答:

var controller = new OrdersController();
var context = new Mock<System.Web.HttpContextBase>().Object;

controller.Url = new UrlHelper(
    new RequestContext(context, new RouteData()),
    new RouteCollection()
);
Run Code Online (Sandbox Code Playgroud)

这不会设置controller.HttpContext属性,但它允许Url.Action执行(并返回一个空字符串——不需要模拟)。