Skip to main content

Command Palette

Search for a command to run...

Mocking ASP.NET MVC's ExceptionContext - aka How to mock global exception filter.

Updated
3 min read
Mocking ASP.NET MVC's ExceptionContext - aka How to mock global exception filter.

The Challenge

Recently at work, I implemented a global exception filter using ASP.NET MVC (System.Web.Mvc) that implements IExceptionFilter to capture and handle any uncaught exceptions. I'm a big fan of this approach for APIs because it allows exceptions to bubble up naturally—developers can focus on business logic instead of worrying about catching and handling unexpected exceptions everywhere.

The implementation itself is straightforward:

internal sealed class GlobalExceptionFilterAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext exceptionContext)
    {
        if (exceptionContext == null)
            return;

        // Handle exception: set response code, content, logging, etc.

        // Mark exception as handled so MVC doesn't rethrow it
        exceptionContext.ExceptionHandled = true;
    }
}

But when it came time to write unit tests, I hit a snag. I don't typically mock MVC pipeline components, so this had me scratching my head. How do I mock ExceptionContext? Where do I even begin?

Working Backwards from the Constructor

My approach to solving this was simple: follow the dependency chain. When you need to mock a complex object, start by examining its constructor.

Looking at the ExceptionContext constructor documentation, I found it requires two parameters:

public ExceptionContext(ControllerContext controllerContext, Exception exception)

Okay, so I need:

  1. A ControllerContext

  2. An Exception

The Exception part is easy—I can use any standard exception like InvalidOperationException or ArgumentNullException. But what about ControllerContext?

Digging Deeper into ControllerContext

Next, I looked at the ControllerContext constructor:

public ControllerContext(HttpContextBase httpContext, RouteData routeData, ControllerBase controller)

Now the dependency chain becomes clearer. To create a ControllerContext, I need:

  1. HttpContextBase

  2. RouteData

  3. ControllerBase

The Complete Mock Setup

With this understanding, I could build my mock setup step by step:

private void SetupMockHttpContext()
{
    // Create stubs for all HTTP context components
    _mockHttpContext = MockRepository.GenerateStub<HttpContextBase>();
    _mockRequest = MockRepository.GenerateStub<HttpRequestBase>();
    _mockResponse = MockRepository.GenerateStub<HttpResponseBase>();
    _mockControllerBase = MockRepository.GenerateStub<ControllerBase>();

    // Wire up the relationships since I may need response and request in my unit test
    _mockHttpContext.Stub(x => x.Request).Return(_mockRequest);
    _mockHttpContext.Stub(x => x.Response).Return(_mockResponse);
}

private void CreateExceptionContext()
{
    _exception = new InvalidOperationException("Error Test Message");
    _exceptionContext = new ExceptionContext(
        new ControllerContext(_mockHttpContext, new RouteData(), _mockControllerBase),_exception);
}

I’m using the Rhino Mock so the syntax maybe a little different but if you are using the Moq library, the idea should be the same in term of the objects you need to mock up.

Key Takeaways

When faced with mocking a complex object:

  1. Start with the constructor - Look up the documentation to understand what dependencies are required

  2. Follow the chain - If a dependency has its own dependencies, examine those constructors too

  3. Work backwards - Build from the innermost dependencies outward

  4. Mock what matters - You don't always need to mock every property; focus on what your code actually uses

In this case, the dependency chain looked like:

ExceptionContext
└── ControllerContext
    ├── HttpContextBase
    │   ├── Request
    │   └── Response
    ├── RouteData
    └── ControllerBase
└── Exception

The Working Test

Here's how it all comes together in an actual test:

[Test]
public void OnException_WhenServiceResponseException_HandlesExceptionCorrectly()
{
    // Arrange
    SetupMockHttpContext();
    _exception = new MyCustomException(
        new HttpResponseMessage(HttpStatusCode.BadRequest),
        "Reason",
        "Error",
        new Exception());
    CreateExceptionContext();

    // Act
    _sut.OnException(_exceptionContext);

    // Assert
    Assert.That(_exceptionContext.ExceptionHandled, Is.True);
    Assert.That(_exceptionContext.Result, Is.Not.Null);
}

The moral of the story? Don't be intimidated by complex framework objects. Take it one dependency at a time, and even the most nested mock setups become manageable.