How do you mock the session object collection using Moq
I started with Scott Hanselman's MVCMockHelper, added a small class and made the modifications shown below to allow the controller to use Session normally and the unit test to verify the values that were set by the controller.
/// <summary>
/// A Class to allow simulation of SessionObject
/// </summary>
public class MockHttpSession : HttpSessionStateBase
{
Dictionary<string, object> m_SessionStorage = new Dictionary<string, object>();
public override object this[string name]
{
get { return m_SessionStorage[name]; }
set { m_SessionStorage[name] = value; }
}
}
//In the MVCMockHelpers I modified the FakeHttpContext() method as shown below
public static HttpContextBase FakeHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new MockHttpSession();
var server = new Mock<HttpServerUtilityBase>();
context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session);
context.Setup(ctx => ctx.Server).Returns(server.Object);
return context.Object;
}
//Now in the unit test i can do
AccountController acct = new AccountController();
acct.SetFakeControllerContext();
acct.SetBusinessObject(mockBO.Object);
RedirectResult results = (RedirectResult)acct.LogOn(userName, password, rememberMe, returnUrl);
Assert.AreEqual(returnUrl, results.Url);
Assert.AreEqual(userName, acct.Session["txtUserName"]);
Assert.IsNotNull(acct.Session["SessionGUID"]);
It's not perfect but it works enough for testing.
Using Moq 3.0.308.2 here is an example of my account controller setup in my unit test:
private AccountController GetAccountController ()
{
.. setup mocked services..
var accountController = new AccountController (..mocked services..);
var controllerContext = new Mock<ControllerContext> ();
controllerContext.SetupGet(p => p.HttpContext.Session["test"]).Returns("Hello World");
controllerContext.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(_testEmail);
controllerContext.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);
controllerContext.SetupGet(p => p.HttpContext.Response.Cookies).Returns(new HttpCookieCollection ());
controllerContext.Setup (p => p.HttpContext.Request.Form.Get ("ReturnUrl")).Returns ("sample-return-url");
controllerContext.Setup (p => p.HttpContext.Request.Params.Get ("q")).Returns ("sample-search-term");
accountController.ControllerContext = controllerContext.Object;
return accountController;
}
then within your controller method the following should return "Hello World"
string test = Session["test"].ToString ();
I just found a nice example of how the Oxite team fakes their HttpSessionState and maintains a SessionStateItemCollection collection within that fake. This should work just as well as a moq in my case.
EDIT:
URL for this example is http://oxite.codeplex.com/sourcecontrol/changeset/view/33871?projectName=oxite#388065
I've made a slightly more elaborate Mock than the answer posted by @RonnBlack
public class HttpSessionStateDictionary : HttpSessionStateBase
{
private readonly NameValueCollection keyCollection = new NameValueCollection();
private readonly Dictionary<string, object> _values = new Dictionary<string, object>();
public override object this[string name]
{
get { return _values.ContainsKey(name) ? _values[name] : null; }
set { _values[name] = value; keyCollection[name] = null;}
}
public override int CodePage
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
public override HttpSessionStateBase Contents
{
get { throw new NotImplementedException(); }
}
public override HttpCookieMode CookieMode
{
get { throw new NotImplementedException(); }
}
public override int Count
{
get { return _values.Count; }
}
public override NameObjectCollectionBase.KeysCollection Keys
{
get { return keyCollection.Keys; }
}
public Dictionary<string, object> UnderlyingStore
{
get { return _values; }
}
public override void Abandon()
{
_values.Clear();
}
public override void Add(string name, object value)
{
_values.Add(name, value);
}
public override void Clear()
{
_values.Clear();
}
public override void CopyTo(Array array, int index)
{
throw new NotImplementedException();
}
public override bool Equals(object obj)
{
return _values.Equals(obj);
}
public override IEnumerator GetEnumerator()
{
return _values.GetEnumerator();
}
public override int GetHashCode()
{
return (_values != null ? _values.GetHashCode() : 0);
}
public override void Remove(string name)
{
_values.Remove(name);
}
public override void RemoveAll()
{
_values.Clear();
}
public override void RemoveAt(int index)
{
throw new NotImplementedException();
}
public override string ToString()
{
return _values.ToString();
}
public bool Equals(HttpSessionStateDictionary other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(other._values, _values);
}
}