2009-12-06 22 views
2

我正在編寫針對ASP.NET MVC應用程序的單元測試,特別是測試了我編寫的HtmlHelper擴展方法。還有就是擴展方法內的一行:如何獲得單元測試以在ASP.NET MVC中使用路線?

var innerHtml = htmlHelper.ActionLink(text, action, controller, routeValues, null); 

當我運行此我的單元測試的內部,生成的URL的href爲空不管通過動作或控制器的

這裏我的單元測試:

var page = CreateProductDataPage(); //returns ProductDataPage object 
var htmlHelper = Http.CreateHtmlHelperWithMocks<ProductDataPage>(new ViewDataDictionary<ProductDataPage>(page), false); 
var result = htmlHelper.ProductListingBreadcrumb(true, null, null); 

這裏是CreateHtmlHelperWithMocks方法:

public static HtmlHelper<T> CreateHtmlHelperWithMocks<T>(ViewDataDictionary<T> viewData, bool isLoggedIn) where T : class 
{ 
    var mockViewDataContainer = new Mock<IViewDataContainer>(); 
    mockViewDataContainer.SetupGet(v => v.ViewData).Returns(viewData); 

    return new HtmlHelper<T>(GetViewContextMock(viewData, isLoggedIn).Object, mockViewDataContainer.Object); 
} 

最後,這裏是GetViewContextMock方法:

public static Mock<ViewContext> GetViewContextMock(ViewDataDictionary viewData, bool isLoggedIn) 
{ 
    var mock = new Mock<ViewContext>(); 

    mock.SetupGet(v => v.HttpContext).Returns(GetHttpContextMock(isLoggedIn).Object); 
    mock.SetupGet(v => v.Controller).Returns(new Mock<ControllerBase>().Object); 
    mock.SetupGet(v => v.View).Returns(new Mock<IView>().Object); 
    mock.SetupGet(v => v.ViewData).Returns(viewData); 
    mock.SetupGet(v => v.TempData).Returns(new TempDataDictionary()); 
    mock.SetupGet(v => v.RouteData).Returns(new RouteData()); 

    return mock; 
} 

回答

4

更新:想通了。在$ $$是多麼痛苦。如果其他人試圖這樣做...

第一步是在創建模擬HtmlHelper時從global.asax添加Route集合。

public static HtmlHelper<T> CreateHtmlHelperWithMocks<T>(ViewDataDictionary<T> viewData, bool isLoggedIn) where T : class 
    { 
     var mockViewDataContainer = new Mock<IViewDataContainer>(); 
     mockViewDataContainer.SetupGet(v => v.ViewData).Returns(viewData); 

     //These next two lines are key: 
     var routeCollection = new RouteCollection(); 
     MvcApplication.RegisterRoutes(routeCollection); 

     return new HtmlHelper<T>(GetViewContextMock(viewData, isLoggedIn).Object, mockViewDataContainer.Object, routeCollection); 
    } 

然後,我必須確保的HttpContext模擬了該請求的ApplicationPath屬性和響應的ApplyAppPathModifier方法所返回的結果。

public static Mock<HttpContextBase> GetHttpContextMock(bool isLoggedIn) 
    { 
     var context = new Mock<HttpContextBase>(); 
     var request = new Mock<HttpRequestBase>(); 
     var response = new Mock<HttpResponseBase>(); 
     var session = new Mock<HttpSessionStateBase>(); 
     var server = new Mock<HttpServerUtilityBase>(); 
     var principal = AuthenticationAndAuthorization.GetPrincipleMock(isLoggedIn); 

     //These next two lines are required for the routing to generate valid URLs, apparently: 
     request.SetupGet(r => r.ApplicationPath).Returns("/"); 
     response.Setup(r => r.ApplyAppPathModifier(It.IsAny<string>())).Returns((string r) => r); 

     context.SetupGet(c => c.Request).Returns(request.Object); 
     context.SetupGet(c => c.Response).Returns(response.Object); 
     context.SetupGet(c => c.Session).Returns(session.Object); 
     context.SetupGet(c => c.Server).Returns(server.Object); 
     context.SetupGet(c => c.User).Returns(principal.Object); 

     return context; 
    } 
+0

非常感謝!你節省了我的一天/晚上/晚上。我同意,多麼痛苦。是的,他們介紹了爲嘲笑開放的接口和基類,但這並不意味着它們變得容易。 – 2010-10-09 21:39:06

0

我的博客上講述大約一個月前與Rhino.Mocks這樣做。你可以在http://farm-fresh-code.blogspot.com/2009/10/mocking-htmlhelper-class-with.html找到更多關於我如何處理這個問題的信息。基本上,我的解決方案是提供模擬中的所有內容,無論是在RouteData中,還是通過連接到模擬助手的Response對象上的ApplyAppPathModifier。它實際上更多的是基於底層存根的假冒助手。

+0

我認爲你在那篇文章中放棄的觀點正是我現在想要克服的一點......我一直在看MVC源代碼,因爲他們直接在那裏測試ActionLink,但是我無法弄清楚我缺少的是什麼。 – mkedobbs 2009-12-06 22:39:11

相關問題