2010-08-04 62 views
1

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

我有嘲笑的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做功:

​​

对于参考ENCE,这是我实现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; 
} 

这里是我的应用程序的Global.asax中定义我的路线:

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

有没有人遇到这样?我错过了什么吗?

编辑:

我已经试过了MVC编码到其手中的路由处理掉,以System.Routing点,并发现了一些很有趣的。而一个极其相似的变体返回预期的字符串

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

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

我不能说MVC最终运行查找所需的URL(凝聚,当然)的代码返回一个空字符串似乎在底层代码中进一步了解了实际发生的情况,但认为它可以帮助某人了解我缺少的设置。 (我不会大声疾呼,因为事实表明UrlHelpers在真正的HttpContext中工作)

+0

什么是你想在这里测试?它看起来像你的测试正在验证MVC框架的UrlHelper类正确地与路由系统对话。在我看来,你不应该为此进行测试,因为MVC团队已经对它进行了测试。 – marcind 2010-08-04 19:46:45

+0

我试图简化仅用于演示文稿的设置,以便我不必显示控制器/操作代码以显示我遇到的问题。我的“真实”设置在我的控制器动作中有Url.RouteUrl调用,我的测试正在检查ViewResult的ViewData.Model中的值。但是,我提供的代码导致了相同的结果。 – 2010-08-04 20:00:42

回答

1

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

我曾尝试将此解决方案piece-meal早期加入,但效果不佳。一旦我完全复制并修改了我的情况,它就完美了。

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

用法:

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; 
}