Question

I'm having problems returning a Session value set from mocking using Moq. Using the following

public class TestHelpers
{
 public long sessionValue = -1;
 public HttpContextBase FakeHttpContext()
 {

  var httpContext = new Mock<HttpContextBase>();
  var session = new Mock<HttpSessionStateBase>();
  httpContext.Setup(x => x.Session).Returns(session.Object);
  httpContext.SetupGet(x => x.Session["id"]).Returns(sessionValue);
  httpContext.SetupSet(x => x.Session["id"] = It.IsAny<long>())
        .Callback((string name, object val) =>
        {
           sessionValue = (long)val;
        });
  }
}

When I try to obtain the value outside using

var th = new TestHelpers();
HttpContextBase httpContext = th.FakeHttpContext();

do some stuff that sets Session["id"]

var sessionid = httpContext.Session["id"];

sessionid turns out to be -1. But I can obtain the set session value using

th.sessionValue

What's wrong? Can't I simply return the set value via Moq?

Was it helpful?

Solution

I need to stop answering my own questions. It turns out that I needed to mock Session["id"] again like so ...

httpContext.SetupSet(x => x.Session["id"] = It.IsAny<long>())
        .Callback((string name, object val) =>
        {
           sessionValue = (long)val;
           httpContext.SetupGet(x => x.Session["id"]).Returns(sessionValue);
        });

OTHER TIPS

Moq's Setup methods do not work with indexed properties that have string indexes. See here: How to MOQ an Indexed property

It's because you're returning the value in the getter which was passed by value. So everytime you invoke the getter, you get the same value returned.

Change the Returns() to use a delegate so it is evaluated every time. That way you will get the correct value every time :)

Much easier on the eye than a SetupGet embedded inside a SetupSet.

httpContext.SetupSet(x => x.Session["id"] = It.IsAny<long>())
        .Callback((string name, object val) => sessionValue = (long)val);
httpContext.SetupGet(x => x.Session["id"]).Returns(() => sessionValue);

I just spent long time trying to figure out the easiest way to do it with moq, below is a copy past of my code that actually worked for me :

var _adminctrl = new Moq.Mock<AdminController>(); //AdminController is my MVC controller

var mock = new Mock<ControllerContext>();
mock.Object.Controller = _adminctrl.Object;
mock.Setup(p => p.HttpContext.Session["UserInfoKey"]).Returns(new ViewModel());
 //here is the catch, attaching the ControllerContext to your controller
_adminctrl.Object.ControllerContext = mock.Object;

hope this helps!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top