Click here to Skip to main content
15,886,049 members
Articles / DevOps / Testing

Unit testing HttpContext.Current outside of a Controller

Rate me:
Please Sign up or sign in to vote.
4.30/5 (5 votes)
5 Jan 2016CPOL2 min read 21K   6   2
Article discussing how to unit test HttpContext.Current outside of a controller

How well do you test your code? Maybe you're a TDD ninja. Perhaps you're just trying to develop the habit of unit testing. You're trying to break away from mocking up an HTML page just for testing. Trouble is, you've fallen at the first hurdle. You're writing a test against code that calls HttpContext. Well, HttpContext.Current to be exact. And the test fails. How frustrating is that? It's not even your code! In this post I'll walk you through a simple technique to make HttpContext.Current testable.

We need to access HttpContext in all sorts of situations when developing MVC applications. Most of the time we access it within a Controller, but sometimes we need it outside of that. We're looking to write unit tests for the majority of our code. This means that we need to test code that calls HttpContext.Current. As soon as we do that, we get the dreaded NullReferenceException and our test fails. The way we get around that is to mock it.

So what is mocking?

Mocking is a technique that allows us to swap out the object we can't test with one that we can. It's an important part of unit testing. Why? Because it allows us to ignore code that's outside of the class we're testing (the code under test). The key to unit testing is to test the smallest piece of code that you can. If the code calls other parts of the system or third party classes, we want to ignore those. We do that by mocking them. Whenever the code calls an object outside of our code under test, we mock it. In effect, we ask the mocking framework to give us an object of the same type instead. Our test code is then in control of what happens with that object.

The problem is, unless we use TypeMock Isolator, we can't mock HttpContext. Why? Because it's a concrete type. Most mocking frameworks (here I'm thinking MOQ, Rhino Mocks and NSubstitute) only allow us to mock abstract classes, interfaces and virtual methods. This encourages us to write code with loose coupling. But it can make testing tricky.

Show me the code!

One solution to our problem is to wrap HttpContext.Current within a class that we can mock. We do this by using HttpContextWrapper, which is of type HttpContextBase, an abstract class. This means we can mock it. So we can test it. Hurrah! Here's a class we can use:

using System.Web;

public interface IContextWrapper
{
    HttpContextBase Current { get; }
    HttpRequestBase Request { get; }
    HttpResponseBase Response { get; }
    HttpServerUtilityBase Server { get; }
}

public class ContextWrapper : IContextWrapper
{
    public HttpContextBase Current
    {
        get
        {
            var httpContext = HttpContext.Current;
            return httpContext == null ? null : new HttpContextWrapper(httpContext);
        }
    }

    public HttpRequestBase Request
    {
        get { return Current.Request; }
    }

    public HttpResponseBase Response
    {
        get { return Current.Response; }
    }

    public HttpServerUtilityBase Server
    {
        get { return Current.Server; }
    }
}

I'm exposing a few common properties (Request, Response and Server) but they're optional. As long as we expose Current as HttpContextBase then we're fine. Whenever we need to use HttpContext.Current, we can inject our wrapper class instead. This allows us to do things like getting the username of the current logged in user (for example):

public class AddUserViewModelFactory : IViewModelFactory<AddUserViewModel>
{
    private readonly IContextWrapper contextWrapper
    public AddUserViewModelFactory(IContextWrapper contextWrapper)
    {
        this.contextWrapper = contextWrapper;
    }

    public AddUserViewModel Create()
    {
        var currentUser = contextWrapper.Current.User.Identity.Name;
    }
}

View original article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead Levelnis Ltd
United Kingdom United Kingdom
Follow along my journey as I create a newsletter about launching websites. Just message me with "I'm in" and I'll add you

Comments and Discussions

 
QuestionUsage of HttpContext.Current from Action method is wrong at all Pin
Alexander Iskhakov5-Jan-16 23:55
Alexander Iskhakov5-Jan-16 23:55 
GeneralMy vote of 5 Pin
Camilo Reyes3-Jan-16 6:03
professionalCamilo Reyes3-Jan-16 6:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.