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:
A ControllerContext
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:
HttpContextBase
RouteData
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:
Start with the constructor - Look up the documentation to understand what dependencies are required
Follow the chain - If a dependency has its own dependencies, examine those constructors too
Work backwards - Build from the innermost dependencies outward
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.



