I read some of the answers on here re: testing views and controllers, and mocking, but I still can't figure out how to test an ASP.NET MVC controller that reads and sets Session values (or any other context based variables.) How do I provide a (Session) context for my test methods? Is mocking the answer? Anybody have examples? Basically, I'd like to fake a session before I call the controller method and have the controller use that session. Any ideas?
7 Answers
Check out Stephen Walther's post on Faking the Controller Context:
ASP.NET MVC Tip #12 – Faking the Controller Context
[TestMethod]
public void TestSessionState()
{
// Create controller
var controller = new HomeController();
// Create fake Controller Context
var sessionItems = new SessionStateItemCollection();
sessionItems["item1"] = "wow!";
controller.ControllerContext = new FakeControllerContext(controller, sessionItems);
var result = controller.TestSession() as ViewResult;
// Assert
Assert.AreEqual("wow!", result.ViewData["item1"]);
// Assert
Assert.AreEqual("cool!", controller.HttpContext.Session["item2"]);
}

- 64,141
- 14
- 108
- 120

- 3,604
- 3
- 37
- 54
-
3I had to dig for this url, so here it is: http://stephenwalther.com/blog/archive/2008/07/01/asp-net-mvc-tip-12-faking-the-controller-context.aspx – blu Apr 10 '09 at 01:57
-
3It might not be obvious, but FakeControllerContext is a custom class. You can see the source for that here: http://stephenwalther.com/Downloads/Tips/Tip12/Tip12.zip – Judah Gabriel Himango May 06 '11 at 21:05
-
The source link above seems to be dead.. anyone have a copy? – Flores Aug 13 '13 at 10:06
-
1[http://web.archive.org/web/*/http://stephenwalther.com/Downloads/Tips/Tip12/Tip12.zip](http://web.archive.org/web/*/http://stephenwalther.com/Downloads/Tips/Tip12/Tip12.zip) – Jacob Jul 07 '14 at 19:56
-
Jacob, you are a Hero Among Men. The code still works wonderfully, as long as you use Controllerbase instead of Icontroller – Bjørn Otto Vasbotten Aug 21 '14 at 21:08
-
Why do you have to create a FakeControllerContext when a real ControllerContext exist in the Framework ? – Rushino May 18 '16 at 20:49
-
For anyone else looking for the source to the `FakeControllerContext` and related classes: https://github.com/sergejusb/DotNetGroup/tree/master/Tests/Fakes – codechurn Aug 10 '16 at 18:31
The ASP.NET MVC framework is not very mock-friendly (or rather, requires too much setup to mock properly, and causes too much friction when testing, IMHO) due to it's use of abstract base classes instead of interfaces. We've had good luck writing abstractions for per-request and session-based storage. We keep those abstractions very light and then our controllers depend upon those abstractions for per-request or per-session storage.
For example, here's how we manage the forms auth stuff. We have an ISecurityContext:
public interface ISecurityContext
{
bool IsAuthenticated { get; }
IIdentity CurrentIdentity { get; }
IPrincipal CurrentUser { get; set; }
}
With a concrete implementation like:
public class SecurityContext : ISecurityContext
{
private readonly HttpContext _context;
public SecurityContext()
{
_context = HttpContext.Current;
}
public bool IsAuthenticated
{
get { return _context.Request.IsAuthenticated; }
}
public IIdentity CurrentIdentity
{
get { return _context.User.Identity; }
}
public IPrincipal CurrentUser
{
get { return _context.User; }
set { _context.User = value; }
}
}

- 3,800
- 21
- 29
With MVC RC 1 the ControllerContext wraps the HttpContext and exposes it as a property. This makes mocking much easier. To mock a session variable with Moq do the following:
var controller = new HomeController();
var context = MockRepository.GenerateStub<ControllerContext>();
context.Expect(x => x.HttpContext.Session["MyKey"]).Return("MyValue");
controller.ControllerContext = context;
See Scott Gu's post for more details.

- 75,180
- 37
- 119
- 173
I found mocking to be fairly easy. Here is an example of mocking the httpContextbase (that contains the request, session and response objects) using moq.
[TestMethod]
public void HowTo_CheckSession_With_TennisApp() {
var request = new Mock<HttpRequestBase>();
request.Expect(r => r.HttpMethod).Returns("GET");
var httpContext = new Mock<HttpContextBase>();
var session = new Mock<HttpSessionStateBase>();
httpContext.Expect(c => c.Request).Returns(request.Object);
httpContext.Expect(c => c.Session).Returns(session.Object);
session.Expect(c => c.Add("test", "something here"));
var playerController = new NewPlayerSignupController();
memberController.ControllerContext = new ControllerContext(new RequestContext(httpContext.Object, new RouteData()), playerController);
session.VerifyAll(); // function is trying to add the desired item to the session in the constructor
//TODO: Add Assertions
}
Hope that helps.

- 1,788
- 2
- 18
- 29
-
2Wow, that's a lot of work just to mock one method :) This is clearly the "too much setup" smell, and it's a result of using abstract base classes rather than interfaces as dependency seams. – chadmyers Oct 06 '08 at 23:18
-
1Sure, I have seen a few projects where they put the setup code in a "helper" class and use it over and over again. – Korbin Oct 07 '08 at 22:24
-
FYI, if your test needs so much setup that you need a 'helper' class, you're going to have pain and friction down the line. – chadmyers Oct 09 '08 at 05:03
Scott Hanselman has a post about how to create a file upload quickapp with MVC and discusses moking and specifically addresses "How to mock things that aren't mock friendly."

- 9,748
- 3
- 39
- 41
I used the following solution - making a controller that all my other controllers inherit from.
public class TestableController : Controller
{
public new HttpSessionStateBase Session
{
get
{
if (session == null)
{
session = base.Session ?? new CustomSession();
}
return session;
}
}
private HttpSessionStateBase session;
public class CustomSession : HttpSessionStateBase
{
private readonly Dictionary<string, object> dictionary;
public CustomSession()
{
dictionary = new Dictionary<string, object>();
}
public override object this[string name]
{
get
{
if (dictionary.ContainsKey(name))
{
return dictionary[name];
} else
{
return null;
}
}
set
{
if (!dictionary.ContainsKey(name))
{
dictionary.Add(name, value);
}
else
{
dictionary[name] = value;
}
}
}
//TODO: implement other methods here as needed to forefil the needs of the Session object. the above implementation was fine for my needs.
}
}
Then use the code as follows:
public class MyController : TestableController { }

- 15,031
- 23
- 100
- 187
Because HttpContext is static, I use Typemock Isolator to mock it, Typemock also has an Add-in custom built for ASP.NET unit testing called Ivonna .