代码之家  ›  专栏  ›  技术社区  ›  mkedobbs

如何让单元测试在ASP.NET MVC中使用路由?

  •  2
  • mkedobbs  · 技术社区  · 15 年前

    我正在编写针对我的ASP.NET MVC应用程序的单元测试,特别是我正在测试我编写的HTMLHelper扩展方法。扩展方法中有一行:

    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;
    }
    
    2 回复  |  直到 15 年前
        1
  •  4
  •   mkedobbs    15 年前

    更新:解决了。美元真是太贵了。万一有人想这么做…

    第一步是在创建mock htmlhelper时添加global.asax中的路由集合。

        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模拟的结果是为请求返回的 应用路径 属性和响应 应用程序路径修改器 方法。

        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;
        }
    
        2
  •  0
  •   tvanfosson    15 年前

    我在博客上写了关于和犀牛一起做这个的事。大约一个月前嘲弄过。有关我如何处理此问题的更多信息,请访问 http://farm-fresh-code.blogspot.com/2009/10/mocking-htmlhelper-class-with.html .基本上,我的解决方案是提供模拟中的所有内容,包括路由数据和通过连接到模拟助手的响应对象上的ApplyAppPathModifier。实际上,它更像是一个基于底层存根的假助手。