with tutorial started route net mvc maphttproute asp .net unit-testing asp.net-web-api action-filter

tutorial - ¿Cómo se puede probar un filtro de acción en ASP.NET Web Api?



route asp net web api (5)

Aquí hay un ejemplo de trabajo de 2018 (.NET Framework 4.5.1). Utiliza un ExceptionFilterAttribute pero debería ser similar para otros FilterAttributes.

[Test] public void MyTest() { var request = new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.google.com")); var response = new HttpResponseMessage(); // This next line is necessary to avoid the following error // if you call `context.Request.CreateResponse(...)` inside the filter: // System.InvalidOperationException: The request does not have an associated configuration object or the provided configuration was null. // Discovered from https://stackoverflow.com/a/44447355/3312114 request.SetConfiguration(new HttpConfiguration()); var context = ContextUtil.GetActionExecutedContext(request, response); _myFilter.OnException(context); // Execute your methods Assert.AreEqual(HttpStatusCode.InternalServerError, context.Response.StatusCode); // Make your assertions }

Luego solo copie la clase ContextUtil en su proyecto de prueba en alguna parte. El comentario de @ thomasb sobre la respuesta de @tugberk sugiere que el último código está aspnetwebstack.codeplex.com/SourceControl/latest#test/… . Si bien ese comentario fue en 2014, por lo que incluso puede haber código posterior, el código de 2014 funcionó para mí (en enero de 2018) mientras que el código original no lo hizo. He copiado la versión posterior a continuación para mayor comodidad. Simplemente colócalo en un nuevo archivo.

internal static class ContextUtil { public static HttpControllerContext CreateControllerContext(HttpConfiguration configuration = null, IHttpController instance = null, IHttpRouteData routeData = null, HttpRequestMessage request = null) { HttpConfiguration config = configuration ?? new HttpConfiguration(); IHttpRouteData route = routeData ?? new HttpRouteData(new HttpRoute()); HttpRequestMessage req = request ?? new HttpRequestMessage(); req.SetConfiguration(config); req.SetRouteData(route); HttpControllerContext context = new HttpControllerContext(config, route, req); if (instance != null) { context.Controller = instance; } context.ControllerDescriptor = CreateControllerDescriptor(config); return context; } public static HttpActionContext CreateActionContext(HttpControllerContext controllerContext = null, HttpActionDescriptor actionDescriptor = null) { HttpControllerContext context = controllerContext ?? ContextUtil.CreateControllerContext(); HttpActionDescriptor descriptor = actionDescriptor ?? CreateActionDescriptor(); descriptor.ControllerDescriptor = context.ControllerDescriptor; return new HttpActionContext(context, descriptor); } public static HttpActionContext GetHttpActionContext(HttpRequestMessage request) { HttpActionContext actionContext = CreateActionContext(); actionContext.ControllerContext.Request = request; return actionContext; } public static HttpActionExecutedContext GetActionExecutedContext(HttpRequestMessage request, HttpResponseMessage response) { HttpActionContext actionContext = CreateActionContext(); actionContext.ControllerContext.Request = request; HttpActionExecutedContext actionExecutedContext = new HttpActionExecutedContext(actionContext, null) { Response = response }; return actionExecutedContext; } public static HttpControllerDescriptor CreateControllerDescriptor(HttpConfiguration config = null) { if (config == null) { config = new HttpConfiguration(); } return new HttpControllerDescriptor() { Configuration = config, ControllerName = "FooController" }; } public static HttpActionDescriptor CreateActionDescriptor() { var mock = new Mock<HttpActionDescriptor>() { CallBase = true }; mock.SetupGet(d => d.ActionName).Returns("Bar"); return mock.Object; } }

Estaba buscando agregar un filtro de acción a mi servicio para manejar la adición de datos de enlace al mensaje de respuesta. He descubierto que necesito simular HttpActionExecutedContext, pero es una clase difícil de simular, ¿cómo te enfrentas a las pruebas de filtro de acción?


Solo uno nuevo.

private HttpActionContext CreateExecutingContext() { return new HttpActionContext { ControllerContext = new HttpControllerContext { Request = new HttpRequestMessage() } }; } private HttpActionExecutedContext CreateExecutedContextWithStatusCode(HttpStatusCode statusCode) { return new HttpActionExecutedContext { ActionContext = new HttpActionContext { ControllerContext = new HttpControllerContext { Request = new HttpRequestMessage() } }, Response = new HttpResponseMessage { StatusCode = statusCode, Content = new StringContent("blah") } }; }


También me he golpeado la cabeza contra una pared de ladrillo. Intenté ActionFilterAttributeTest pero seguí obteniendo una excepción de referencia nula. Descubrí cómo llamar a ActionFilter en esta publicación. NB: ActionFilter no se invocaba cuando se usaba una instancia de Mock del filtro. Tenía que usar el objeto real. HTH

Específicamente:

var httpActionContext = new HttpActionContext { ControllerContext = new HttpControllerContext { Request = requestMessage } }; //call filter var filter = new FooFilter(); filter.OnActionExecuting(httpActionContext);


Tuve el mismo problema al intentar probar un filtro personalizado de excepción no controlada que había creado.

Esto hizo el truco. Un montón de novedades y una larga línea de código.

var httpActionExecutedContext = new HttpActionExecutedContext( new HttpActionContext( new HttpControllerContext( new HttpConfiguration(), Substitute.For<IHttpRouteData>(), new HttpRequestMessage()), Substitute.For<HttpActionDescriptor>()), null);

Se usó NSubstiute, pero cualquier marco burlón de su elección que maneje clases base abstractas estaría bien.

Espero que esto ayude


Puede crear una falsificación para HttpActionExecutedContext siguiente manera:

public static HttpActionContext CreateActionContext(HttpControllerContext controllerContext = null, HttpActionDescriptor actionDescriptor = null) { HttpControllerContext context = controllerContext ?? ContextUtil.CreateControllerContext(); HttpActionDescriptor descriptor = actionDescriptor ?? new Mock<HttpActionDescriptor>() { CallBase = true }.Object; return new HttpActionContext(context, descriptor); } public static HttpActionExecutedContext GetActionExecutedContext(HttpRequestMessage request, HttpResponseMessage response) { HttpActionContext actionContext = CreateActionContext(); actionContext.ControllerContext.Request = request; HttpActionExecutedContext actionExecutedContext = new HttpActionExecutedContext(actionContext, null) { Response = response }; return actionExecutedContext; }

Acabo de copiar y pegar ese código del código fuente de ASP.NET Web API: clase ContextUtil . Aquí hay algunos ejemplos de cómo probaron algunos filtros incorporados:

ActionFilterAttributeTest es la clase de prueba para ActionFilterAttribute que es una clase abstracta pero obtendrás la idea.