How to Successfully Mock HttpContext

For web developers, mocking an HttpContext is one of the hardest things to do. Today, I use two mocking frameworks to show you a number of ways to mock the HttpContext.

August 14th, 2015 • MVC •
3 (1 votes)
Mocking Face

Since I've been using ASP.NET MVC, I've learned a lot about unit testing in the past 5 years (and a lot of that credit goes to Jon Kruger), but with all of that learning, I keep hearing about developers who have trouble with mocking HttpContext.

You always need to make sure that your code runs as independent as possible. Your environment can, and will, change. Therefore, you need to match the environment as much as possible to make your code work in an environment that isn't connected.

An environment that isn't connected? Whaaaaaat? What does that mean?

Your unit tests should run with no external resources. Zip. Zilch. Nada. None!

If you are connecting to a database, these are called integration tests. The database can be down for maintenance and your unit tests would fail.

Same for files on a hard drive. Integration test. The file is mandatory or the hard drive fills up and runs out of space. Unit test fails.

Same for accessing the Internet. External resource...integration test. Network is down. Dead unit test.

Unit tests should run on a machine with no connections to any external resources. Period.

Mocking Frameworks

So how do we test HttpContext without connecting to the Internet?

That is where our mocking frameworks enter the picture: Moq and RhinoMocks.

Both are important, but I think Moq is taking the lead based on the strong typing syntax instead of RhinoMocks' magic strings.

To show the similarities, I will be providing both Moq and Rhino Mocks examples.

Time to Mock the HttpContext

When we mock an object, what we are really saying is that we are creating dummy objects that mimic the behavior of real objects in our system. We want our dummy objects to act just like we're are using them in a production environment.

The baseline for mocking the HttpContext is pretty simple. We attach our TestInitialize attribute to our method and create our variables.

[TestClass]
public class MockingHttpContextTest
{
    private HttpContextBase rmContext;
    private HttpRequestBase rmRequest;
    private Mock<HttpContextBase> moqContext;
    private Mock<HttpRequestBase> moqRequest;
    [TestInitialize]
    public void SetupTests()
    {
        // Setup Rhino Mocks
        rmContext = MockRepository.GenerateMock<HttpContextBase>();
        rmRequest = MockRepository.GenerateMock<HttpRequestBase>();
        rmContext.Stub(x => x.Request).Return(rmRequest);
        // Setup Moq
        moqContext = new Mock<HttpContextBase>();
        moqRequest = new Mock<HttpRequestBase>();
        moqContext.Setup(x => x.Request).Returns(moqRequest.Object);
    }

Now we can start mocking our ASP.NET MVC routines very easily with a mocked-up HttpContext.

Routing

Since routing is deconstructed from the HttpContext, unit testing routes makes things a little more difficult, but we have a mocked HttpContext!

Routing is strictly used from the AppRelativeCurrentExecutionFilePath property (Phew! that's a mouthful) so we need to mock just that property.

#region Routing Tests
[TestMethod]
public void RhinoMocksRoutingTest()
{
    // Arrange
    RouteCollection routes = new RouteCollection();
    RouteConfig.RegisterRoutes(routes);
    rmRequest.Stub(e => e.AppRelativeCurrentExecutionFilePath).Return("~/Home/Index");
    // Act
    RouteData routeData = routes.GetRouteData(rmContext);
    // Assert
    Assert.IsNotNull(routeData);
    Assert.AreEqual("Home",routeData.Values["controller"]);
    Assert.AreEqual("Index",routeData.Values["action"]);
}
[TestMethod]
public void MoqRoutingTest()
{
    // Arrange
    RouteCollection routes = new RouteCollection();
    RouteConfig.RegisterRoutes(routes);
    moqRequest.Setup(e => e.AppRelativeCurrentExecutionFilePath).Returns("~/Home/Index");
    // Act
    RouteData routeData = routes.GetRouteData(moqContext.Object);
    // Assert
    Assert.IsNotNull(routeData);
    Assert.AreEqual("Home", routeData.Values["controller"]);
    Assert.AreEqual("Index", routeData.Values["action"]);
}
#endregion

Sorry, but I included regions because we'll have more unit tests.

Forms and QueryStrings

While we could test to see if this data was submitted successfully through the controller, a better test is to make sure our request returns the right form data and query strings.

I've made another alteration to the SetupTests method at the top to accommodate our form/querystring values (in bold).

private NameValueCollection formValues;
[TestInitialize]
public void SetupTests()
{
    // Setup Rhino Mocks
    rmContext = MockRepository.GenerateMock<HttpContextBase>();
    rmRequest = MockRepository.GenerateMock<HttpRequestBase>();
    rmContext.Stub(x => x.Request).Return(rmRequest);
    // Setup Moq
    moqContext = new Mock<HttpContextBase>();
    moqRequest = new Mock<HttpRequestBase>();
    moqContext.Setup(x => x.Request).Returns(moqRequest.Object);
    // Create a "fake" form
    formValues = new NameValueCollection
    {
        { "FirstName""Jonathan" }, 
        { "LastName""Danylko" }                
    };
}

While it may seem like a simple task to place the data and retrieve it back out, it confirms that we have our HttpContext and HttpRequest mocks objects setup properly.

#region Forms Tests
[TestMethod]
public void RhinoMocksFormsTest()
{
    // Arrange            
    rmRequest.Stub(r => r.Form).Return(formValues);
    
    // Act
    var forms = rmContext.Request.Form;  
    
    // Assert
    Assert.IsNotNull(forms);
    Assert.AreEqual("Jonathan", forms["FirstName"]);
    Assert.AreEqual("Danylko", forms["LastName"]);
}
[TestMethod]
public void MoqFormsTest()
{
    // Arrange            
    moqRequest.Setup(r => r.Form).Returns(formValues);
    // Act
    var forms = moqContext.Object.Request.Form;
    // Assert
    Assert.IsNotNull(forms);
    Assert.AreEqual("Jonathan", forms["FirstName"]);
    Assert.AreEqual("Danylko", forms["LastName"]);
}
#endregion
#region QueryString Tests
[TestMethod]
public void RhinoMocksQueryStringTest()
{
    // Arrange            
    rmRequest.Stub(r => r.QueryString).Return(formValues);
    // Act
    var queryString = rmContext.Request.QueryString;
    // Assert
    Assert.IsNotNull(queryString);
    Assert.AreEqual("Jonathan", queryString["FirstName"]);
    Assert.AreEqual("Danylko", queryString["LastName"]);
}
[TestMethod]
public void MoqQueryStringTest()
{
    // Arrange            
    moqRequest.Setup(r => r.QueryString).Returns(formValues);
    // Act
    var queryString = moqContext.Object.Request.QueryString;
    // Assert
    Assert.IsNotNull(queryString);
    Assert.AreEqual("Jonathan", queryString["FirstName"]);
    Assert.AreEqual("Danylko", queryString["LastName"]);
}
#endregion

BTW, this would also work with cookies.

Server Variables

Server Variables can be manipulated as well using a NameValueCollection.

Why would you want to test Server Variables?

If you want to test your code to display something if someone came from Google with a query search, you can display a message saying "Coming From Google? Thanks for visiting. Check out these links."

You would definitely want to Unit Test that functionality. Of course, you could use the Request.UrlReferrer, but I'm trying to prove a point that you could unit test Server Variables. ;-)

#region Server Variable Tests
[TestMethod]
public void RhinoMocksServerVariableTest()
{
    // Arrange            
    rmRequest.Stub(x => x.Url).Return(new Uri("http://localhost"));
    rmRequest.Stub(x => x.ServerVariables).Return(new NameValueCollection
    {
        {"SERVER_NAME""localhost"},
        {"SCRIPT_NAME""localhost"},
        {"SERVER_PORT""80"},
        {"REMOTE_ADDR""127.0.0.1"},
        {"REMOTE_HOST""127.0.0.1"}
    });
    
    // Act
    var variables = rmContext.Request.ServerVariables;
    
    // Assert
    Assert.IsNotNull(variables);
    Assert.AreEqual("localhost", variables["SERVER_NAME"]);
}
[TestMethod]
public void MoqServerVariableTest()
{
    // Arrange            
    moqRequest.Setup(x => x.Url).Returns(new Uri("http://localhost"));
    moqRequest.Setup(x => x.ServerVariables).Returns(new NameValueCollection
    {
        {"SERVER_NAME""localhost"},
        {"SCRIPT_NAME""localhost"},
        {"SERVER_PORT""80"},
        {"REMOTE_ADDR""127.0.0.1"},
        {"REMOTE_HOST""127.0.0.1"}
    });
    // Act
    var variables = moqContext.Object.Request.ServerVariables;
    // Assert
    Assert.IsNotNull(variables);
    Assert.AreEqual("localhost", variables["SERVER_NAME"]);
}
#endregion

ControllerContext

Finally, we will create a mock ControllerContext. If you are doing any kind of controller unit tests, this is an absolute must.

For those new to unit testing ASP.NET MVC, you can't create a controller without a ControllerContext. It passes in the HttpContext (for the url information), the Routing Data (to compare with the url), and the actual controller for executing a method.

Once we have all three of those parameters, we can mock a ControllerContext.

#region ControllerContext
[TestMethod]
public void RhinoMocksControllerContextTest()
{
    // Arrange
    var controller = new SubscribeController();
    var context = new ControllerContext(rmContext, new RouteData(), controller);
    controller.ControllerContext = context;
    var parameters = new SubscribeParameter();
    // Act
    var result = controller.SignUp(parameters) as ProcessResult<SubscribeParameter>;
    // Use ViewResult here for your results. This is a specific ActionResult I built.
    // Assert
    Assert.IsNotNull(result);
}
[TestMethod]
public void MoqControllerContextTest()
{
    // Arrange
    var controller = new SubscribeController();
    controller.ControllerContext = new ControllerContext(moqContext.Object, new RouteData(), controller);
    var parameters = new SubscribeParameter();
    // Act
    var result = controller.SignUp(parameters) as ProcessResult<SubscribeParameter>;
    // Use ViewResult here for your results. This is a specific ActionResult I built.
    
    // Assert
    Assert.IsNotNull(result);
}
#endregion

All we needed was a mocked HttpContext and a single controller to make sure everything worked for your unit test to pass.

The ProcessResult returned is a custom ActionResult I built. For the simple ViewResult, your unit test could check to see if you have a valid ViewModel returning from the ViewResult.

Conclusion

I hope this post simplifies the mocking of the HttpContext using either Moq or RhinoMocks. Once you see the pattern, it gets easier and easier to write unit tests.

The amount of unit tests for ASP.NET MVC can be staggering, but you can easily mock up any object for any test. The more you write, the better you'll become.

You just need to stick with it to write quality code.

Did I miss an MVC hook that I didn't cover in this post? Make me aware of it! Let me know in the comments below. 

Was this informative? Share it!

Looking to become a better developer?

Sign up to receive ReSharper Design Pattern Smart Templates, ASP.NET MVC Guidelines Checklist, and Newsletter Updates!

Picture of Jonathan Danylko

Jonathan Danylko is a freelance web architect and avid programmer who has been programming for over 20 years. He has developed various systems in numerous industries including e-commerce, biotechnology, real estate, health, insurance, and utility companies.

When asked what he likes to do in his spare time, he replies, "Programming."

comments powered by Disqus