I recently spent more time than I'd liked to figure out how to mock session state within an ASP.NET MVC test project. So here's the solution to that one, so hopefully you won't spend as much time as I did.
Important disclaimer: I was all over the dial to search for information, but most of what I dug up was related to ASP.NET MVC 3. This below solution works for me with ASP.NET MVC 4 and Moq as mocking framework.
Consider the following controller and single action-method.
public class HomeController : Controller
{
public HomeController()
{
}
public ViewResult TestMe()
{
System.Diagnostics.Debug.WriteLine(Session["selectedMonth"]);
System.Diagnostics.Debug.WriteLine(Session["selectedYear"]);
return View();
}
}
The action-method references the current httpcontext
's Session
collection. So if we instantiate a HomeController
and try to obtain a ViewResult
when calling the action-method, our unit test will fail with a NullReferenceException
.
So, since the action-method wants to know about the Session
collection, which resides in the HttpContext
for the request to the method, we need to provide a HttpContext
object. The below unit test code creates a mock HttpContext
object, hooks it up to a mock Session
object and passes it the instantiation of the controller - and the test will then pass, as now the action-method has a HttpContext
to reach into and yank out the Session
information.
[TestMethod]
public void TestActionMethod()
{
var fakeHttpContext = new Mock();
var sessionMock = new HttpSessionMock {{"selectedYear", 2013}, {"selectedMonth", 10}};
var mockSessionState = new Mock();
fakeHttpContext.Setup(ctx => ctx.Session).Returns(sessionMock);
var fakeIdentity = new GenericIdentity("mno@ucsj.dk");
var principal = new GenericPrincipal(fakeIdentity, null);
fakeHttpContext.Setup(t => t.User).Returns(principal);
var homeControllerMock = new Mock();
homeControllerMock.Setup(foo => foo.HttpContext).Returns(fakeHttpContext.Object);
var target = new HomeController()
{
ControllerContext = homeControllerMock.Object
};
ViewResult result = target.TestMe();
Assert.AreEqual(string.empty, result.ViewName);
}