How can you unit test an Action Filter in ASP.NET Web Api?
You can create a fake for HttpActionExecutedContext
as below:
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;
}
I just copied and pasted that code from the ASP.NET Web API source code: ContextUtil class. Here is a few examples on how they tested some built in filters:
AuthorizeAttributeTest
ActionFilterAttributeTest
ActionFilterAttributeTest
is the test class for ActionFilterAttribute
which is an abstract class but you will get the idea.
Just new one up.
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")
}
};
}
I had the same problem when trying to test a custom unhandled exception filter I had built.
This did the trick. Lots of newing up and a very long line of code.
var httpActionExecutedContext = new HttpActionExecutedContext(
new HttpActionContext(
new HttpControllerContext(
new HttpConfiguration(),
Substitute.For<IHttpRouteData>(),
new HttpRequestMessage()),
Substitute.For<HttpActionDescriptor>()),
null);
NSubstiute was used, but any mocking framework of your choice that handles abstract base classes would be fine.
Hope this helps
I've been banging my head against a brick wall over this also. I tried contextUtil but kept getting a null reference exception. I found out how to call an actionFilter in this post N.B. The actionFilter wasn't being invoked when using a Mock instance of the filter, I had to use the real object. HTH
Specifically:
var httpActionContext = new HttpActionContext
{
ControllerContext = new HttpControllerContext
{
Request = requestMessage
}
};
//call filter
var filter = new FooFilter();
filter.OnActionExecuting(httpActionContext);