• Testing MVC Controllers with HttpContext

    Published by on March 9th, 2012 8:29 pm under C#, MVC, Testing

    No Comments

    So there I was… having fun, writing unit tests, when suddenly the code I’m testing throws:

    image

    ouch… the Controller was working just fine. What is this “Response” and why is it ‘null’ when I’m doing unit tests?

    Easy, Response is a property of type HttpResponseBase, from the Controller class, which holds the data of the  response that will be sent to the client in the current HTTP Request. HttpContext is the class that holds the entire HTTP request data.

    As there is NO HTTP request in a unit test, the HttpContext is never set in the Controller. So if we have, for example, a method that builds information into the Response, it will throw an exception as shown earlier.

    But our problems, don’t end there…

    If we analyze the hierarchy of the Controller class and the HttpContext class, we discover that the HttpContext is actually set with a HttpContextBase, in the ControllerContext property of the type ControllerContext. HttpContextBase is abstract an cannot be instantiated… so what do we do?

    Mock it!

    using Moq;
    
    public void MockHttpContextBase(Controller controller)
            {
                var server = new Mock<HttpServerUtilityBase>(MockBehavior.Loose);
                var response = new Mock<HttpResponseBase>(MockBehavior.Loose);
                var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
                request.Setup(r => r.UserHostAddress).Returns("127.0.0.1");
                
                var session = new Mock<HttpSessionStateBase>();
                session.Setup(s => s.SessionID).Returns(Guid.NewGuid().ToString());
    
                var context = new Mock<HttpContextBase>();
                context.SetupGet(c => c.Request).Returns(request.Object);
                context.SetupGet(c => c.Response).Returns(response.Object);
                context.SetupGet(c => c.Server).Returns(server.Object);
                context.SetupGet(c => c.Session).Returns(session.Object);
    
                controller.ControllerContext = new ControllerContext(
                                                    context.Object,
                                                    new RouteData(),
                                                    controller);
            }
    

    Basically I created a method that receives a controller, creates the necessary mocks and finally creates a new ControllerContext and the assigns it to the Controller’s ControllerContext property.

    And that’s it!

    Source:

    http://weblogs.asp.net/gunnarpeipman/archive/2011/07/16/using-moq-to-mock-asp-net-mvc-httpcontextbase.aspx