How can you unit test an Action Filter in ASP.NET Web Api?

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);

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.


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


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")
        }
    };
}