测试路由配置在ASP.NET的WebAPI [英] Testing route configuration in ASP.NET WebApi

查看:128
本文介绍了测试路由配置在ASP.NET的WebAPI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图做我的的WebAPI 路由配置一些单元测试。我想测试,该航线/ API /超级映射到我的<$的的get()方法C $ C> SuperController 。我设置了以下测试时遇到的几个问题。

公共无效GetTest()
{
    VAR URL =〜/ API /超;    VAR routeCollection =新HttpRouteCollection();
    routeCollection.MapHttpRoute(DefaultApi,API / {控制器} /);    VAR httpConfig =新HttpConfiguration(routeCollection);
    VAR要求=新的Htt prequestMessage(HttpMethod.Get,URL);    //异常时,URL =/ API /超
    //可以避开瓦特/设置URL =HTTP://本地主机/ API /超
    VAR的RouteData = httpConfig.Routes.GetRouteData(请求);
    request.Properties [HttpPropertyKeys.HttpRouteDataKey] =的RouteData;    VAR controllerSelector =新DefaultHttpControllerSelector(httpConfig);    VAR controlleDescriptor = controllerSelector.SelectController(请求);    VAR controllerContext =
        新HttpControllerContext(httpConfig,的RouteData,请求);
    controllerContext.ControllerDescriptor = controlleDescriptor;    VAR选择=新ApiControllerActionSelector();
    VAR actionDescriptor = selector.SelectAction(controllerContext);    Assert.AreEqual(typeof运算(SuperController)
        controlleDescriptor.ControllerType);
    Assert.IsTrue(actionDescriptor.ActionName ==获取);
}

我的第一个问题是,如果我不指定一个完全合格的URL httpConfig.Routes.GetRouteData(请求); 抛出一个出现InvalidOperationException 与消息异常不支持相对URI此操作。

我显然缺少与我的存根配置的东西。我想preFER使用相对URI作为它似乎没有合理的使用完全合格的URI路由测试。

我上面我的配置第二个问题,我没有测试我的路由作为配置在我RouteConfig但我不是用:

VAR routeCollection =新HttpRouteCollection();
routeCollection.MapHttpRoute(DefaultApi,API / {控制器} /);

我如何使用分配的 RouteTable.Routes 中配置的一个典型的Global.asax:

公共类MvcApplication:一个HttpApplication
{
    保护无效的Application_Start()
    {
        //其他启动的东西        RouteConfig.RegisterRoutes(RouteTable.Routes);
    }
}公共类RouteConfig
{
    公共静态无效的RegisterRoutes(RouteCollection路线)
    {
        //路由配置
    }
}

另外上面我所掐灭可能不是最好的测试配置。如果有一个更精简的方法,我洗耳恭听。


解决方案

我最近测试我的Web API的路线,这里是我是怎么做的。


  1. 首先,我创建了一个帮手,搬到那里所有的Web API路由逻辑:

公共静态类的WebAPI
    {
        公共静态RouteInfo RouteRequest(HttpConfiguration配置,Htt的prequestMessage要求)
        {
            //创建上下文
            VAR controllerContext =新HttpControllerContext(配置,Substitute.For&LT; IHttpRouteData&GT;(),请求);            //获取路线数据
            VAR的RouteData = config.Routes.GetRouteData(请求);
            RemoveOptionalRoutingParameters(routeData.Values​​);            request.Properties [HttpPropertyKeys.HttpRouteDataKey] =的RouteData;
            controllerContext.RouteData =的RouteData;            //获取控制器类型
            VAR controllerDescriptor =新DefaultHttpControllerSelector(配置).SelectController(请求);
            controllerContext.ControllerDescriptor = controllerDescriptor;            //获取操作名称
            。VAR的ActionMapping =新ApiControllerActionSelector()SelectAction(controllerContext);            返回新RouteInfo
            {
                控制器= controllerDescriptor.ControllerType,
                行动= actionMapping.ActionName
            };
        }        私有静态无效RemoveOptionalRoutingParameters(IDictionary的&LT;字符串对象&gt; routeValues​​)
        {
            VAR optionalParams = routeValues
                。凡(X =&GT; x.Value == RouteParameter.Optional)
                。选择(X =&GT; x.Key)
                .ToList();            的foreach(在optionalParams VAR键)
            {
                routeValues​​.Remove(键);
            }
        }
    }    公共类RouteInfo
    {
        公共型控制器{搞定;组; }        公共字符串操作{搞定;组; }
    }


  1. 假设我有一个单独的类来注册的Web API的路线(它在默认情况下在Visual Studio ASP.NET MVC 4 Web应用程序项目创建的,在App_Start文件夹):

公共静态类WebApiConfig
    {
        公共静态无效的注册(HttpConfiguration配置)
        {
            config.Routes.MapHttpRoute(
                名称:DefaultApi
                routeTemplate:API / {}控制器/(编号),
                默认:新{ID = RouteParameter.Optional}
            );
        }
    }


  1. 我可以轻松地测试我的路线:

[测试]
    公共无效GET_api_products_by_id_Should_route_to_ProductsController_Get_method()
    {
        //设置
        VAR要求=新的Htt prequestMessage(HttpMethod.Gethttp://myshop.com/api/products/1);
        无功配置=新HttpConfiguration();        //行为
        WebApiConfig.Register(配置);
        VAR路线= WebApi.RouteRequest(配置,请求);        //断言
        。route.Controller.Should()成为&LT;&ProductsController的GT;();
        。route.Action.Should()BE(获取);
    }    [测试]
    公共无效GET_api_products_Should_route_to_ProductsController_GetAll_method()
    {
        //设置
        VAR要求=新的Htt prequestMessage(HttpMethod.Gethttp://myshop.com/api/products);
        无功配置=新HttpConfiguration();        //行为
        WebApiConfig.Register(配置);
        VAR路线= WebApi.RouteRequest(配置,请求);        //断言
        。route.Controller.Should()成为&LT;&ProductsController的GT;();
        。route.Action.Should()BE(GETALL);
    }    ....

下面的一些注意事项:


  • 是的,我使用的是绝对URL。但我看不出有任何问题,在这里,因为这些都是假的网址,我不需要配置任何东西为他们工作,他们重新给我们的网络服务presenting真正的请求。

  • 您不需要您的路由映射code复制到测试,如果他们在与HttpConfiguration依赖单独的类配置(如上面的例子)。

  • 我使用NUnit,NSubstitute并在上面的例子中FluentAssertions,但当然是一件容易的事做同样与任何其他测试框架。

I am trying to do some unit testing of my WebApi route configuration. I want to test that the route "/api/super" maps to the Get() method of my SuperController. I've setup the below test and am having a few issues.

public void GetTest()
{
    var url = "~/api/super";

    var routeCollection = new HttpRouteCollection();
    routeCollection.MapHttpRoute("DefaultApi", "api/{controller}/");

    var httpConfig = new HttpConfiguration(routeCollection);
    var request = new HttpRequestMessage(HttpMethod.Get, url);

    // exception when url = "/api/super"
    // can get around w/ setting url = "http://localhost/api/super"
    var routeData = httpConfig.Routes.GetRouteData(request);
    request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData;

    var controllerSelector = new DefaultHttpControllerSelector(httpConfig);

    var controlleDescriptor = controllerSelector.SelectController(request);

    var controllerContext =
        new HttpControllerContext(httpConfig, routeData, request);
    controllerContext.ControllerDescriptor = controlleDescriptor;

    var selector = new ApiControllerActionSelector();
    var actionDescriptor = selector.SelectAction(controllerContext);

    Assert.AreEqual(typeof(SuperController),
        controlleDescriptor.ControllerType);
    Assert.IsTrue(actionDescriptor.ActionName == "Get");
}

My first issue is that if I don't specify a fully qualified URL httpConfig.Routes.GetRouteData(request); throws a InvalidOperationException exception with a message of "This operation is not supported for a relative URI."

I'm obviously missing something with my stubbed configuration. I would prefer to use a relative URI as it does not seem reasonable to use a fully qualified URI for route testing.

My second issue with my configuration above is I am not testing my routes as configured in my RouteConfig but am instead using:

var routeCollection = new HttpRouteCollection();
routeCollection.MapHttpRoute("DefaultApi", "api/{controller}/");

How do I make use of the assigned RouteTable.Routes as configured in a typical Global.asax:

public class MvcApplication : HttpApplication
{
    protected void Application_Start()
    {
        // other startup stuff

        RouteConfig.RegisterRoutes(RouteTable.Routes);
    }
}

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        // route configuration
    }
}

Further what I have stubbed out above may not be the best test configuration. If there is a more streamlined approach I am all ears.

解决方案

I was recently testing my Web API routes, and here is how I did that.

  1. First, I created a helper to move all Web API routing logic there:

    public static class WebApi
    {
        public static RouteInfo RouteRequest(HttpConfiguration config, HttpRequestMessage request)
        {
            // create context
            var controllerContext = new HttpControllerContext(config, Substitute.For<IHttpRouteData>(), request);

            // get route data
            var routeData = config.Routes.GetRouteData(request);
            RemoveOptionalRoutingParameters(routeData.Values);

            request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData;
            controllerContext.RouteData = routeData;

            // get controller type
            var controllerDescriptor = new DefaultHttpControllerSelector(config).SelectController(request);
            controllerContext.ControllerDescriptor = controllerDescriptor;

            // get action name
            var actionMapping = new ApiControllerActionSelector().SelectAction(controllerContext);

            return new RouteInfo
            {
                Controller = controllerDescriptor.ControllerType,
                Action = actionMapping.ActionName
            };
        }

        private static void RemoveOptionalRoutingParameters(IDictionary<string, object> routeValues)
        {
            var optionalParams = routeValues
                .Where(x => x.Value == RouteParameter.Optional)
                .Select(x => x.Key)
                .ToList();

            foreach (var key in optionalParams)
            {
                routeValues.Remove(key);
            }
        }
    }

    public class RouteInfo
    {
        public Type Controller { get; set; }

        public string Action { get; set; }
    }

  1. Assuming I have a separate class to register Web API routes (it is created by default in Visual Studio ASP.NET MVC 4 Web Application project, in the App_Start folder):

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }

  1. I can test my routes easily:

    [Test]
    public void GET_api_products_by_id_Should_route_to_ProductsController_Get_method()
    {
        // setups
        var request = new HttpRequestMessage(HttpMethod.Get, "http://myshop.com/api/products/1");
        var config = new HttpConfiguration();

        // act
        WebApiConfig.Register(config);
        var route = WebApi.RouteRequest(config, request);

        // asserts
        route.Controller.Should().Be<ProductsController>();
        route.Action.Should().Be("Get");
    }

    [Test]
    public void GET_api_products_Should_route_to_ProductsController_GetAll_method()
    {
        // setups
        var request = new HttpRequestMessage(HttpMethod.Get, "http://myshop.com/api/products");
        var config = new HttpConfiguration();

        // act
        WebApiConfig.Register(config);
        var route = WebApi.RouteRequest(config, request);

        // asserts
        route.Controller.Should().Be<ProductsController>();
        route.Action.Should().Be("GetAll");
    }

    ....

Some notes below:

  • Yes, I'm using absolute URLs. But I don't see any issues here, because these are fake URLs, I don't need to configure anything for them to work, and they representing real requests to our web services.
  • You don't need to copy you route mappings code to the tests, if they are configured in the separate class with HttpConfiguration dependency (like in the example above).
  • I'm using NUnit, NSubstitute and FluentAssertions in the above example, but of course it's an easy task to do the same with any other test frameworks.

这篇关于测试路由配置在ASP.NET的WebAPI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆