How do you mock the session object collection using Moq

前端 未结 7 540
忘了有多久
忘了有多久 2020-11-28 22:08

I am using shanselmann\'s MvcMockHelper class to mock up some HttpContext stuff using Moq but the issue I am having is being able to assign something to my mocked session ob

相关标签:
7条回答
  • 2020-11-28 22:25

    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

    0 讨论(0)
  • 2020-11-28 22:28

    Just for Session easier way is to create Session object in parent class and use it like this

        public class DalBl : IDalBl
    {
        public dynamic Session
        {
            get { return HttpContext.Current.Session; }
        }
    }
    

    and in unitTest

                var session = new  Dictionary<string, object>();
            var moq = new Moq.Mock<IDalBl>();
            moq.Setup(d => d.Session).Returns(session);
    
    0 讨论(0)
  • 2020-11-28 22:30

    I think you can set an expectation on the mock with a specific value it should return whatever. Mocks are not used as actual fakes but rather things that you can assert behavior on.

    It sounds like you are actually looking for an adapter that you can wrap around the session that you can supply a different implementation during tests and during runtime it would return HttpContext Session items?

    Does this make sense?

    0 讨论(0)
  • 2020-11-28 22:32

    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.

    0 讨论(0)
  • 2020-11-28 22:36

    Thank you, @RonnBlack for your solution! In my case, I kept getting this exception because Session.SessionID was null:

    System.NotImplementedException was unhandled by user code
      HResult=-2147467263
      Message=The method or operation is not implemented.
      Source=System.Web
      StackTrace:
           at System.Web.HttpSessionStateBase.get_SessionID()
    

    To solve this problem I implement @RonnBlack's code this way using the Moq Mock<HttpSessionStateBase> instead of his MockHttpSession:

        private readonly MyController controller = new MyController();
    
        [TestFixtureSetUp]
        public void Init()
        {
            var session = new Mock<HttpSessionStateBase>();
            session.Setup(s => s.SessionID).Returns(Guid.NewGuid().ToString());
            var request = new Mock<HttpRequestBase>();
            var response = new Mock<HttpResponseBase>();
            var server = new Mock<HttpServerUtilityBase>();
            // Not working - IsAjaxRequest() is static extension method and cannot be mocked
            // request.Setup(x => x.IsAjaxRequest()).Returns(true /* or false */);
            // use this
            request.SetupGet(x => x.Headers).Returns(
                new System.Net.WebHeaderCollection
                {
                    {"X-Requested-With", "XMLHttpRequest"}
                });
    
            var context = new Mock<HttpContextBase>();
            //context
            context.Setup(ctx => ctx.Request).Returns(request.Object);
            context.Setup(ctx => ctx.Response).Returns(response.Object);
            context.Setup(ctx => ctx.Session).Returns(session.Object);
            context.Setup(ctx => ctx.Server).Returns(server.Object);
            context.SetupGet(x => x.Request).Returns(request.Object);
            context.SetupGet(p => p.Request.Url).Returns(new Uri("http://www.mytesturl.com"));
            var queryString = new NameValueCollection { { "code", "codeValue" } };
            context.SetupGet(r => r.Request.QueryString).Returns(queryString);
    
            controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
        }
    

    For details, please see http://weblogs.asp.net/gunnarpeipman/using-moq-to-mock-asp-net-mvc-httpcontextbase

    0 讨论(0)
  • 2020-11-28 22:41

    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 ();
    
    0 讨论(0)
提交回复
热议问题