Asp.net-mvc – ASP.NET MVC unit test controller with HttpContext

asp.net-mvcunit testing

I am trying to write a unit test for my one controller to verify if a view was returned properly, but this controller has a basecontroller that accesses the HttpContext.Current.Session. Everytime I create a new instance of my controller is calls the basecontroller constructor and the test fails with a null pointer exception on the HttpContext.Current.Session. Here is the code:

public class BaseController : Controller
{       
    protected BaseController()
    {
       ViewData["UserID"] = HttpContext.Current.Session["UserID"];   
    }
}

public class IndexController : BaseController
{
    public ActionResult Index()
    {
        return View("Index.aspx");
    }
}

    [TestMethod]
    public void Retrieve_IndexTest()
    {
        // Arrange
        const string expectedViewName = "Index";

        IndexController controller = new IndexController();

        // Act
        var result = controller.Index() as ViewResult;

        // Assert
        Assert.IsNotNull(result, "Should have returned a ViewResult");
        Assert.AreEqual(expectedViewName, result.ViewName, "View name should have been {0}", expectedViewName);
    }

Any ideas on how to mock (using Moq) the Session that is accessed in the base controller so the test in the descendant controller will run?

Best Answer

Unless you use Typemock or Moles, you can't.

In ASP.NET MVC you are not supposed to be using HttpContext.Current. Change your base class to use ControllerBase.ControllerContext - it has a HttpContext property that exposes the testable HttpContextBase class.

Here's an example of how you can use Moq to set up a Mock HttpContextBase:

var httpCtxStub = new Mock<HttpContextBase>();

var controllerCtx = new ControllerContext();
controllerCtx.HttpContext = httpCtxStub.Object;

sut.ControllerContext = controllerCtx;

// Exercise and verify the sut

where sut represents the System Under Test (SUT), i.e. the Controller you wish to test.