测试路由配置在ASP.NET的WebAPI [英] Testing route configuration in 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的路线,这里是我是怎么做的。
- 首先,我创建了一个帮手,搬到那里所有的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
{
公共型控制器{搞定;组; } 公共字符串操作{搞定;组; }
}
- 假设我有一个单独的类来注册的Web API的路线(它在默认情况下在Visual Studio ASP.NET MVC 4 Web应用程序项目创建的,在App_Start文件夹):
公共静态类WebApiConfig
{
公共静态无效的注册(HttpConfiguration配置)
{
config.Routes.MapHttpRoute(
名称:DefaultApi
routeTemplate:API / {}控制器/(编号),
默认:新{ID = RouteParameter.Optional}
);
}
}
- 我可以轻松地测试我的路线:
[测试]
公共无效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.
- 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; }
}
- 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 }
);
}
}
- 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屋!