How to Mock HttpContext
Code making direct calls to Asp.Net's HttpContext can be tricky to test since HttpContext is not fully defined in the scope of a unit test. In this article I will demonstrate how to get around this issue by mocking the context and some of its common properties.
I will use a simple tax calculation function to show how to seamlessly mock the call to retrieve the sales tax from HttpSession.
Code listing 1 shows my MVC controller.
public class SalesController : Controller
{
public SalesController():this(new ControllerContext()){}
public SalesController(ControllerContext ctx)
{
this.ControllerContext = ctx;
}
[HttpGet]
public ActionResult CalculatePrice(double priceBeforeTax)
{
double salesTax = (double)this.ControllerContext.HttpContext.Session["SalesTax"];
double priceAfterTax = priceBeforeTax + (priceBeforeTax * salesTax / 100.0);
return View(priceAfterTax);
}
}
Code listing 1
Normally we would have a problem here if we tried to unit test this method since we would get a "not implemented exception" due to the undefined Session object.
The solution is to introduce mocking of HttpContext and Session: In my example I will use a popular mocking framework called MOQ.
Code listing 2 shows my unit test with mocked values for the session backed sales tax:
[Test]
public void WillReturnPriceAfterTaxes()
{
Mock httpContext = new Mock<HttpContextBase>();
Mock session = new Mock<HttpSessionStateBase>();
session.Setup(s => s["SalesTax"]).Returns(4.0);
httpContext.Setup(c => c.Session).Returns(session.Object);
ControllerContext ctx = new ControllerContext();
ctx.HttpContext = httpContext.Object;
SalesController controller = new SalesController(ctx);
ViewResult v = controller.CalculatePrice(10) as ViewResult;
Assert.AreEqual(10.4, v.Model);
}
Code listing 2