代码之家  ›  专栏  ›  技术社区  ›  James Maroney

UrlHelper的RouteUrl在测试中返回空字符串

  •  1
  • James Maroney  · 技术社区  · 16 年前

    我遇到了一个问题,UrlHelper的RouteUrl方法在测试中运行时只返回一个空字符串,但在真正的HttpContext中执行时功能正常。然而,它是在寻找路由——如果我试图解析一个尚未定义的路由名称,我确实会遇到一个异常。

    我嘲笑了HttpContext和使用 code provided by Scott Hanselman/Kzu 并添加了 code needed to bootstrap the Application's Routes 进入模拟的实例

    为了减少我的情况中的变量数量,我编写了一个简单的测试:

    [Test]
    public void UrlHelperReturnsCorrectUrl()
    {
      var controller = new MyController();
      controller.SetFakeControllerContext().LoadUrlHelper();
    
      Assert.AreEqual("My/Route/Path", controller.Url.RouteUrl("MyRoute"));
    }
    

    有趣的是,直接访问RouteCollection并使用VirtualPath确实有效:

    [Test]
    public void GetVirtualPathReturnsCorrectUrl()
    {
        var controller = new AccountController();
        controller.SetFakeControllerContext().LoadUrlHelper();
        Assert.AreEqual("My/Route/Path", 
                   Controller.Url.RouteCollection["MyRoute"]
                   .GetVirtualPath(
                       controller.Url.RequestContext,
                       new RouteValueDictionary())
                   .VirtualPath);
    }
    

    LoadUrlHelper的实现参考如下:

    public static Controller LoadUrlHelper(this Controller controller)
    {
        var routes = new RouteCollection();
        MvcApplication.RegisterRoutes(routes);
        controller.Url = new UrlHelper(
                            controller.ControllerContext.RequestContext, 
                            routes);
        return controller;
    }
    

    这是我在应用程序的全局路径中定义的路径。尽快:

    routes.MapRoute(
       "MyRoute", "My/Route/Path",
       new {controller = "Home", action = "Index"});
    

    有人碰到过这个吗?我错过什么了吗?

    编辑:

    我一直遵循MVC代码,直到它将路由处理交给系统。我发现了一些非常有趣的东西。MVC最终运行以查找所需URL的代码(当然是压缩的)返回一个空字符串:

    Controller.Url.RouteCollection.GetVirtualPath(
              Controller.Url.RequestContext, 
              "MyRoute", new RouteValueDictionary()).VirtualPath;
    

    而一个非常相似的变量返回预期的字符串:

    Controller.Url.RouteCollection["MyRoute"].GetVirtualPath(
              Controller.Url.RequestContext, 
              new RouteValueDictionary()).VirtualPath;
    

    我似乎无法在底层代码中进一步了解这里实际发生的不同情况,但我认为这可能有助于人们理解我缺少的设置。(我还不打算大喊bug,因为事实上,UrlHelpers在真正的HttpContext中是可以工作的)

    1 回复  |  直到 9 年前
        1
  •  1
  •   Community Mohan Dere    9 年前

    我问题的解决方案已经发布到 another SO question .

    早些时候,我曾尝试将这种解决方案整合到一顿饭中,但效果很差。一旦我完全复制了它,并根据我的情况进行了修改,它就完美地工作了。

    这是一个更通用的版本,可以在许多测试中重用(如果放在基本测试夹具类或类似的东西中)。

    用法:

    var controller = GetController<MyController>();
    controller.MyAction();
    //...
    

    方法:

    protected T GetController<T>() where T : Controller, new()
    {
        var routes = new RouteCollection();
        MvcApplication.RegisterRoutes(routes);
    
        var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
        request.SetupGet(x => x.ApplicationPath).Returns("/");
        request.SetupGet(x => x.Url).Returns(new Uri("http://localhost", UriKind.Absolute));
        request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());
    
        var response = new Mock<HttpResponseBase>(MockBehavior.Strict);
        response.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns((string p) => p);
    
        var context = new Mock<HttpContextBase>(MockBehavior.Strict);
        context.SetupGet(x => x.Request).Returns(request.Object);
        context.SetupGet(x => x.Response).Returns(response.Object);
    
        var controller = new T();
        controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
        controller.Url = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes);
    
        return controller;
    }