2010-08-04 19 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; 
}