How to Mock an HttpContext for Unit Testing

I recently made some modifications to a class written by another programmer. When I went to write a unit test for my new additions, I found that the class made use of the statically accessible HttpContext.Current object. For my unit test, I wanted to be able to mock this out and use dependency injection to pass the mock in. Here are the steps I took to accomplish this.

First, a brief summary of the classes I worked with to get this done:
  • HttpContext: The original ASP.NET HttpContext. It has no base class and is not virtual, so it can't be mocked.
  • HttpContextBase: Introduced in .NET 3.5 as a replacement to HttpContext. Abstract, and therefore mockable. This is the type to use as a parameter when injecting.
  • HttpContextWrapper: Also introduced in .NET 3.5, it is an implementation of HttpContextBase. You can instantiate a new instance of this class from an HttpContext by passing the HttpContext into HttpContextWrapper's constructor (Example: new HttpContextWrapper(HttpContext.Current)).

Okay, so the first step I took was to create a member variable in the class I had modified and wanted to unit test of type HttpContextBase:

        private HttpContextBase _httpContext = null
 
Then, I created a new constructor for the class to take an instance of HttpContextBase as a parameter, and assigned it to this variable:

        public MyExampleClass(HttpContextBase httpContext)
        {
            _httpContext = httpContext;
        }
  
To pass in an HttpContext from a web page, you'd need to first wrap it in the aforementioned HttpContextWrapper class. To pass in a mock, you could mock an HttpContextBase (as I'll show further below).

In the default (parameterless) constructor, I assigned HttpContext.Current (if it exists) to this value, wrapped in an instance HttpContextWrapper. This was done to avoid impacting all of the production code that uses the class as originally written. The ideal solution would be to refactor everything to use dependency injection (which I would like to do eventually). I then modified the class to use the new member variable instead of HttpContext.Current.

In my unit test, I was able to use Moq to mock an instance of HttpContextBase, along with a mock request (HttpRequestBase) and Uri (no mock necessary).

        Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
        Mock<HttpRequestBase> mockHttpRequest = new Mock<HttpRequestBase>();
        Uri uri = new Uri("http://www.mytestsite.com/MyAccount/TrackOrder.aspx");
 
        mockHttpRequest.Setup(x => x.Url).Returns(uri);
        mockHttpContext.Setup(x => x.Request).Returns(mockHttpRequest.Object);
 
The mocked HttpContextBase then gets passed into the instance of the class I want to unit test.


Comments

Curt said…
Awesome!

Popular Posts

Resolving the "n timer(s) still in the queue" Error In Angular Unit Tests

Silent Renew and the "login_required" Error When Using oidc-client

How to Get Norton Security Suite Firewall to Allow Remote Desktop Connections in Windows

Fixing the "Please add a @Pipe/@Directive/@Component annotation" Error In An Angular App After Upgrading to webpack 4

How to Determine if a Column Exists in a DataReader