单元测试命中UrlHelper扩展方法始终无法根据路由名称匹配路由

时间:2011-12-29 15:56:50

标签: asp.net asp.net-mvc unit-testing asp.net-mvc-routing

...但是当应用程序本身正在执行时,相同的扩展方法也可以工作。 UrlHelper扩展方法本身如下所示:

    public static string CategoryLandingPage(this UrlHelper helper, string seoCategoryName)
    {
        return helper.RouteUrl("Category", new { area = "SoAndSo", controller = "SoAndSo", action = "Category", seoCategoryName = seoCategoryName }, "http");
    }

我在SoAndSoAreaRegistration类中注册了这样的特定路由:

        context.MapRoute(
           "Category",
           "category/{seoCategoryName}",
           new { area = "SoAndSo", controller = "SoAndSo", action = "Category", seoCategoryName = string.Empty }
        );

...我已经在该注册中删除了一个断点,以确保它被测试运行器击中,并且确实如此。

当我运行测试时,我得到一个ArgumentException,“在路径集合中找不到名为'Category'的路径。参数名称:name”。

我的猜测是我们不需要指定路线名称足够的路线参数(区域/控制器/行动/类别名称)来完整地构建路线,因为我们在这里做,但我无法弄清楚路线名称在测试过程中消失的位置。删除类别名称可以消除异常并允许测试通过,但我仍然希望了解路由名称在测试时消失的位置。像这样简化代码仍然在运行时爆炸:

    public static string CategoryLandingPage(this UrlHelper helper, string seoCategoryName)
    {
        return helper.RouteUrl("Category");            
    }

如果我在运行时挖掘路径集合,我可以找到类别路径,但没有.Name属性的证据,也没有看到路径的名称(带有大写C的“类别”) UrlHelper的属性(为愚蠢的混淆道歉;更好的安全而不是遗憾): code snippet

有没有人知道如何编写单元测试,这些测试会按照名称引用路由的UrlHelper扩展方法?谢谢!

  • 更新 - 我将添加一些测试初始化​​,其中大部分是我从this popular question获得的,经过轻微修改以解释我正在使用的应用程序被分成多个MVC区域的事实:

    private SoAndSoController CreateController() {     var service = new Mock();     var cookieMgr = new Mock();     var logger = new Mock();

    var allRoutes = new RouteCollection();
    MvcApplication.RegisterRoutes(allRoutes);
    var soAndSoAreaRegistration = new SoAndSoAreaRegistration();
    var soAndSoAreaRegistrationContext = new AreaRegistrationContext(soAndSoAreaRegistration.AreaName, new RouteCollection());
    soAndSoAreaRegistration.RegisterArea(soAndSoAreaRegistrationContext);
    soAndSoAreaRegistrationContext.Routes.ForEach(r => allRoutes.Add(r));
    
    var request = new Mock<HttpRequestBase>();
    request.SetupGet(x => x.ApplicationPath).Returns("/");
    request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
    request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());
    
    var response = new Mock<HttpResponseBase>();
    response.Setup(x => x.ApplyAppPathModifier("/post1")).Returns("http://localhost/post1");
    
    var context = new Mock<HttpContextBase>();
    context.SetupGet(x => x.Request).Returns(request.Object);
    context.SetupGet(x => x.Response).Returns(response.Object);
    
    var controller = new SoAndSoController(service.Object, cookieMgr.Object, null, logger.Object, null);
    controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
    controller.Url = new UrlHelper(new RequestContext(context.Object, new RouteData()), allRoutes);
    
    return controller;
    

    }

1 个答案:

答案 0 :(得分:1)

我明白了。我需要将RouteCollection传递给AreaRegistrationContext,而不是传递一个新的RouteCollection:

            var productFindingAreaRegistrationContext = new AreaRegistrationContext(productFindingAreaRegistration.AreaName, allRoutes);

但这导致这条线爆炸:

productFindingAreaRegistrationContext.Routes.ForEach(r => allRoutes.Add(r));

然而现在不再需要这条线,所以我评论了它。瞧。