unit test probar net framework asp c# unit-testing asp.net-web-api

c# - test - ¿Cómo se puede probar el enrutamiento de la API Web ASP.NET?



unit test web api net core (4)

He escrito una publicación en un blog sobre las rutas de prueba y estoy haciendo prácticamente lo que me preguntas:

http://www.strathweb.com/2012/08/testing-routes-in-asp-net-web-api/

Espero eso ayude.

Una ventaja adicional es que utilicé la reflexión para proporcionar métodos de acción, así que en lugar de usar rutas con cadenas, las agrega de manera fuertemente tipada. Con este enfoque, si sus nombres de acción alguna vez cambian, las pruebas no se compilarán, por lo que podrá detectar fácilmente los errores.

Estoy intentando escribir algunas pruebas de unidad para garantizar que las solicitudes realizadas a mi API web se enruten a la acción del controlador API esperado con los argumentos esperados.

Intenté crear una prueba utilizando la clase HttpServer , pero obtuve 500 respuestas del servidor y no hubo información para solucionar el problema.

¿Hay alguna manera de crear pruebas unitarias para el enrutamiento de un sitio ASP.NET Web API?

Idealmente, me gustaría crear una solicitud usando HttpClient y hacer que el servidor maneje la solicitud y pasarla a través del proceso de enrutamiento esperado.


Hola, cuando vayas a probar tus rutas, el objetivo principal es probar GetRouteData () con esta prueba, asegúrate de que el sistema de rutas reconozca correctamente tu solicitud y se seleccione la ruta correcta.

[Theory] [InlineData("http://localhost:5240/foo/route", "GET", false, null, null)] [InlineData("http://localhost:5240/api/Cars/", "GET", true, "Cars", null)] [InlineData("http://localhost:5240/api/Cars/123", "GET", true, "Cars", "123")] public void DefaultRoute_Returns_Correct_RouteData( string url, string method, bool shouldfound, string controller, string id) { //Arrange var config = new HttpConfiguration(); WebApiConfig.Register(config); var actionSelector = config.Services.GetActionSelector(); var controllerSelector = config.Services.GetHttpControllerSelector(); var request = new HttpRequestMessage(new HttpMethod(method), url); config.EnsureInitialized(); //Act var routeData = config.Routes.GetRouteData(request); //Assert // assert Assert.Equal(shouldfound, routeData != null); if (shouldfound) { Assert.Equal(controller, routeData.Values["controller"]); Assert.Equal(id == null ? (object)RouteParameter.Optional : (object)id, routeData. Values["id"]); } }

esto es importante pero no es suficiente, incluso si se verifica que se selecciona la ruta correcta y se extraen los datos de ruta correctos no se garantiza que se seleccionen el controlador y la acción correctos, este es un método útil si no se reescriben los servicios predeterminados IHttpActionSelector e IHttpControllerSelector contigo mismo.

[Theory] [InlineData("http://localhost:12345/api/Cars/123", "GET", typeof(CarsController), "GetCars")] [InlineData("http://localhost:12345/api/Cars", "GET", typeof(CarsController), "GetCars")] public void Ensure_Correct_Controller_and_Action_Selected(string url,string method, Type controllerType,string actionName) { //Arrange var config = new HttpConfiguration(); WebApiConfig.Register(config); var controllerSelector = config.Services.GetHttpControllerSelector(); var actionSelector = config.Services.GetActionSelector(); var request = new HttpRequestMessage(new HttpMethod(method),url); config.EnsureInitialized(); var routeData = config.Routes.GetRouteData(request); request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData; request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config; //Act var ctrlDescriptor = controllerSelector.SelectController(request); var ctrlContext = new HttpControllerContext(config, routeData, request) { ControllerDescriptor = ctrlDescriptor }; var actionDescriptor = actionSelector.SelectAction(ctrlContext); //Assert Assert.NotNull(ctrlDescriptor); Assert.Equal(controllerType, ctrlDescriptor.ControllerType); Assert.Equal(actionName, actionDescriptor.ActionName); } }


La mejor forma de probar sus rutas para su aplicación ASP.NET Web API es la prueba de integración de sus puntos finales.

Aquí hay una muestra simple de prueba de integración para su aplicación ASP.NET Web API. Esto no prueba principalmente tus rutas pero las prueba invisiblemente. Además, estoy usando XUnit, Autofac y Moq aquí.

[Fact, NullCurrentPrincipal] public async Task Returns_200_And_Role_With_Key() { // Arrange Guid key1 = Guid.NewGuid(), key2 = Guid.NewGuid(), key3 = Guid.NewGuid(), key4 = Guid.NewGuid(); var mockMemSrv = ServicesMockHelper .GetInitialMembershipService(); mockMemSrv.Setup(ms => ms.GetRole( It.Is<Guid>(k => k == key1 || k == key2 || k == key3 || k == key4 ) ) ).Returns<Guid>(key => new Role { Key = key, Name = "FooBar" }); var config = IntegrationTestHelper .GetInitialIntegrationTestConfig(GetInitialServices(mockMemSrv.Object)); using (var httpServer = new HttpServer(config)) using (var client = httpServer.ToHttpClient()) { var request = HttpRequestMessageHelper .ConstructRequest( httpMethod: HttpMethod.Get, uri: string.Format( "https://localhost/{0}/{1}", "api/roles", key2.ToString()), mediaType: "application/json", username: Constants.ValidAdminUserName, password: Constants.ValidAdminPassword); // Act var response = await client.SendAsync(request); var role = await response.Content.ReadAsAsync<RoleDto>(); // Assert Assert.Equal(key2, role.Key); Assert.Equal("FooBar", role.Name); } }

Hay algunos ayudantes externos que uso para esta prueba. El uno de ellos es el NullCurrentPrincipalAttribute . Como su prueba se ejecutará con su identidad de Windows, el Thread.CurrentPrincipal se establecerá con esta identidad. Entonces, si está utilizando algún tipo de autorización en su aplicación, lo mejor es deshacerse de esto en primer lugar:

public class NullCurrentPrincipalAttribute : BeforeAfterTestAttribute { public override void Before(MethodInfo methodUnderTest) { Thread.CurrentPrincipal = null; } }

Luego, creo un servicio de MembershipService simulado. Esta es la configuración específica de la aplicación. Por lo tanto, esto se modificará para su propia implementación.

GetInitialServices crea el contenedor Autofac para mí.

private static IContainer GetInitialServices( IMembershipService memSrv) { var builder = IntegrationTestHelper .GetEmptyContainerBuilder(); builder.Register(c => memSrv) .As<IMembershipService>() .InstancePerApiRequest(); return builder.Build(); }

El método GetInitialIntegrationTestConfig solo GetInitialIntegrationTestConfig mi configuración.

internal static class IntegrationTestHelper { internal static HttpConfiguration GetInitialIntegrationTestConfig() { var config = new HttpConfiguration(); RouteConfig.RegisterRoutes(config.Routes); WebAPIConfig.Configure(config); return config; } internal static HttpConfiguration GetInitialIntegrationTestConfig(IContainer container) { var config = GetInitialIntegrationTestConfig(); AutofacWebAPI.Initialize(config, container); return config; } }

El método RouteConfig.RegisterRoutes básicamente registra mis rutas. También tengo un pequeño método de extensión para crear un HttpClient sobre HttpServer .

internal static class HttpServerExtensions { internal static HttpClient ToHttpClient( this HttpServer httpServer) { return new HttpClient(httpServer); } }

Finalmente, tengo una clase estática llamada HttpRequestMessageHelper que tiene un montón de métodos estáticos para construir una nueva instancia de HttpRequestMessage .

internal static class HttpRequestMessageHelper { internal static HttpRequestMessage ConstructRequest( HttpMethod httpMethod, string uri) { return new HttpRequestMessage(httpMethod, uri); } internal static HttpRequestMessage ConstructRequest( HttpMethod httpMethod, string uri, string mediaType) { return ConstructRequest( httpMethod, uri, new MediaTypeWithQualityHeaderValue(mediaType)); } internal static HttpRequestMessage ConstructRequest( HttpMethod httpMethod, string uri, IEnumerable<string> mediaTypes) { return ConstructRequest( httpMethod, uri, mediaTypes.ToMediaTypeWithQualityHeaderValues()); } internal static HttpRequestMessage ConstructRequest( HttpMethod httpMethod, string uri, string mediaType, string username, string password) { return ConstructRequest( httpMethod, uri, new[] { mediaType }, username, password); } internal static HttpRequestMessage ConstructRequest( HttpMethod httpMethod, string uri, IEnumerable<string> mediaTypes, string username, string password) { var request = ConstructRequest(httpMethod, uri, mediaTypes); request.Headers.Authorization = new AuthenticationHeaderValue( "Basic", EncodeToBase64( string.Format("{0}:{1}", username, password))); return request; } // Private helpers private static HttpRequestMessage ConstructRequest( HttpMethod httpMethod, string uri, MediaTypeWithQualityHeaderValue mediaType) { return ConstructRequest( httpMethod, uri, new[] { mediaType }); } private static HttpRequestMessage ConstructRequest( HttpMethod httpMethod, string uri, IEnumerable<MediaTypeWithQualityHeaderValue> mediaTypes) { var request = ConstructRequest(httpMethod, uri); request.Headers.Accept.AddTo(mediaTypes); return request; } private static string EncodeToBase64(string value) { byte[] toEncodeAsBytes = Encoding.UTF8.GetBytes(value); return Convert.ToBase64String(toEncodeAsBytes); } }

Estoy usando Autenticación básica en mi aplicación. Por lo tanto, esta clase tiene algunos métodos que construyen un HttpRequestMessege con el encabezado Autenticación.

Al final, hago mi Acto y Afirmo para verificar las cosas que necesito. Esta puede ser una muestra exagerada pero creo que esto te dará una gran idea.

Aquí hay una excelente publicación de blog sobre pruebas de integración con HttpServer . Además, aquí hay otra gran publicación sobre las http://www.strathweb.com/2012/08/testing-routes-in-asp-net-web-api/ .


Para probar las rutas de ASP.NET Web API, puede usar una herramienta de terceros como MvcRouteTester o MyWebApi . Aquí hay un código de muestra para comenzar:

MyWebApi .Routes() .ShouldMap("api/WebApiController/SomeAction") .WithHttpMethod(HttpMethod.Post) .WithJsonContent(@"{""SomeInt"": 1, ""SomeString"": ""Test""}") .To<WebApiController>(c => c.SomeAction(new RequestModel { SomeInt = 1, SomeString = "Test" }));

Si desea implementar las pruebas usted mismo, puede ver cómo hacer que el solucionador de rutas de la API Web interna correlacione la solicitud por usted. Entonces solo necesita comparar el controlador seleccionado y las acciones. ENLACE AQUÍ .