【问题标题】:ASP.NET MVC: Mock controller.Url.ActionASP.NET MVC:模拟控制器.Url.Action
【发布时间】:2009-09-02 13:11:49
【问题描述】:

我的 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 的全部功能,为什么我需要另一个抽象。

【问题讨论】:

  • 本身不值得回答,所以我会指出一个类似的答案:bit.ly/aSJ0a
  • 是的,我使用了该链接,但它不起作用。实际上我尝试了 Scott 的版本和 MVCContrib。我试图理解的是我需要设置什么值? Url.Action() 实际使用什么? IE。在您提供的链接上,有一个设置了很多变量的 Moq 版本……它们都是必需的吗?我尝试了所有这些都没有运气。
  • 查看有问题的更新...

标签: asp.net-mvc


【解决方案1】:

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

var controller = new OrdersController();
var 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);

干净简单。

【讨论】:

    【解决方案2】:

    以下是使用 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));
    

    【讨论】:

    • 糟糕...在 MSDN 帮助中看到 Controller.Url“获取 URL 帮助器对象”是一种误导...我什至没有验证它是否有设置器。
    • 您知道我们如何使用 MVC4 Darin 实现这一目标吗?因为我正在尝试遵循您的代码示例,但无法调用 RegisterRoutes
    • Tyler:RegisterRoutes 是一个约定,使用 MvcApplication.RouteTable.Routes.Add(...)
    【解决方案3】:

    如果您使用的是Moq(而不是MvcContribTestControllerBuilder),您可以模拟出上下文,类似于@DarianDimitrov 的回答:

    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 属性,但它确实允许Url.Action 执行(并返回一个空字符串——不需要模拟)。

    【讨论】:

      【解决方案4】:

      Fake it easy 效果很好:

       var fakeUrlHelper = A.Fake<UrlHelper>();
              controller.Url = fakeUrlHelper;
              A.CallTo(() => fakeUrlHelper.Action(A<string>.Ignored, A<string>.Ignored))
                  .Returns("/Action/Controller");
      

      【讨论】:

      • +1 亿使用FakeItEasy !!但是...... Action 方法不是虚拟的......所以你怎么能伪造/拦截呢?
      【解决方案5】:

      这是解决 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);
      

      【讨论】:

        猜你喜欢
        • 2010-09-07
        • 2014-10-21
        • 2015-09-08
        • 2010-12-26
        • 1970-01-01
        • 1970-01-01
        • 2015-02-13
        • 2016-03-02
        • 2011-10-15
        相关资源
        最近更新 更多