Break the dependency on HttpContext in order to test web functionality – level 300

HttpContext.Current is very useful, and it’s easy to sprinkle website code with it.  The bad side effect is that code that calls HttpContext.Current cannot be run in a test harness.  This is a big problem.  This post will show how to test code that needs HttpContext.Current.


The key is to break the dependency on HttpContext.Current.  By breaking the dependency, we can run our code in a test harness (like NUnit) and verify that it’s working correct (test harnesses are also great for debugging).  To start breaking the dependency, consider the following code we have:


        public string GetLoggedInUserName()
        {
            return HttpContext.Current.User.Identity.Name;
        }


This code dives right into the ASP.NET API, and code that depends on this method will be impossible to test.  To break this dependency on HttpContext.Current, we have to know what we really need.  We need the user name of the currently logged in user.  We are pulling this from the IPrincipal object.  We’re going to strip out this code and put an interface in it’s place:


    [PluginFamily(“Default”)]
    public interface ICurrentHttpContext
    {
        IPrincipal Principal { get;}
    }  


Next, we need to have a way for the original class to find a class that implements this interface for runtime.  We’ll use StructureMap for the dirt-simple linking through attributes:


    [Pluggable(“Default”)]
    public class CurrentHttpContext : ICurrentHttpContext
    {
        public IPrincipal Principal
        {
            get { return HttpContext.Current.User; }
        }
    }


Now we need to modify the original class with a testing constructor and a default constructor for dependency discovery:


    public class MyThingy
    {
        ICurrentHttpContext _context;
 
        public MyThingy(ICurrentHttpContext context)
        {
            _context = context;
        }
 
        public MyThingy()
        {
            _context = (ICurrentHttpContext) ObjectFactory.GetInstance(typeof(ICurrentHttpContext));
        }
 
        public string GetLoggedInUserName()
        {
            return _context.Principal.Identity.Name;
        }


    }


Notice here that we have a default constructor that asks StructureMap for the right implementation of ICurrentHttpContext, and for a unit test we have the constructor that accepts a mock instance.  This example shows that it is very easy to break a dependency on HttpContext.Current.  We can continue to use the fantastic services of HttpContext.Current while keeping our codebase testable.