Martín Verzilli

Martín Verzilli

How do I unit-test a class which depends on HttpContext?

3 min
Aug 12 2009
testing
3 min
Aug 12 2009

Suppose you have to fix a bug in an ASP.NET application. You’re a TDD-guy so once you identify it, you write a test which should reproduce it. Then you run it and… null pointer exception. Your testing framework may have pointed you to the exact line, so you inspect it and see something like:

var foo = HttpContext.Current.[...];

Then you realize the guy who wrote the buggy class wasn’t a TDD-guy!

You need somehow to be able to inject an HttpContext object so you can run your tests without the need of running a web server. If you can do that, then you just mock it and… wait! HttpContext is a concrete class! So now, what?

Well, ASP.NET MVC comes with the assembly System.Web.Abstractions which adds classes to the System.Web namespace such as HttpContextBase, HttpRequestBase, and other abstractions of ASP.NET intrinsic objects.

Cool! Now you can mock HttpContextBase and inject it to the tested class.

Are you done? Not yet. HttpContextBase is of course a newer class than HttpContext, so not surprisingly HttpContext does not derive from HttpContextBase. Nevertheless, System.Web.Abstractions provides an HttpContextWrapper which does inherit from HttpContextBase and receives an instance of HttpContext through its constructor.

Now all you have to do is encapsulate or your uses of HttpContext.Current in some way that let’s you substitute it for an injected mock transparently for the user code.

In my case, it was more convenient to inject via a setter:

private HttpContextBase context = null;
/// <summary>
/// Allows HttpContext injection, mainly for testing purposes
/// </summary>
public HttpContextBase CurrentHttpContext
{
    get
    {
        context = context ?? new HttpContextWrapper(HttpContext.Current);
        return context;
    }
    set
    {
        context = value;
    }
}

But it would be exactly the same to do it via a constructor. Then, you just have to replace all your HttpContext.Current calls with calls to the property CurrentHttpContext:

var foo = CurrentHttpContext[...];

When you see there’s an assembly called “Abstractions” with abstract classes and wrappers for preexisting concrete or even sealed classes, it becomes obvious that the ASP.NET MVC team has written its code with testability in mind, and that’s great! So kudos to them :)