如何将会话添加到模拟httpcontext?

时间:2011-05-10 10:28:12

标签: asp.net-mvc unit-testing

根据scott hanselman的模拟示例http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx我尝试使用MockHelpers模拟httpcontext作为下面的代码片段

controller = GetAccountController();

ActionResult result = controller.ChangePassword();

HttpContextBase hb = MvcMockHelpers.FakeHttpContext("~/Account/ChangePassword");
hb.Session.Add("id", 5);

// Assert Assert.AreEqual(5, (int)hb.Session["id"]);

我注意到会话未添加,也没有收到任何错误。会话对象的属性低于值

  

Count = 0,CodePage = 0,Content = null,IsCookieLess = null,IsNewSession = null,IsReadOnly = null,IsSynchronized = null,Keys = null,LCID = 0,Mode = off,SessionId = null,Static Objects = null,SynRoot = null,TimeOut = 0

我得到了Rhino mock和Moq的相同结果。

请建议我如何将会话添加到模拟httpcontext。

提前致谢。

5 个答案:

答案 0 :(得分:3)

这是我用来模拟会话,但你需要的大多数其他对象(请求,响应等),这段代码是史蒂夫桑德森和其他人以及我自己的代码的集合,请注意会话是使用字典伪造的

using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;

namespace ECWeb2.UnitTests {
    public class ContextMocks {
        public Moq.Mock<HttpContextBase> HttpContext { get; private set; }
        public Moq.Mock<HttpRequestBase> Request { get; private set; }
        public Moq.Mock<HttpResponseBase> Response { get; private set; }
        public RouteData RouteData { get; private set; }
    public ContextMocks(Controller onController) {
        // Define all the common context objects, plus relationships between them
        HttpContext = new Moq.Mock<HttpContextBase>();
        Request = new Moq.Mock<HttpRequestBase>();
        Response = new Moq.Mock<HttpResponseBase>();
        HttpContext.Setup(x => x.Request).Returns(Request.Object);
        HttpContext.Setup(x => x.Response).Returns(Response.Object);
        HttpContext.Setup(x => x.Session).Returns(new FakeSessionState());
        Request.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
        Response.Setup(x => x.Cookies).Returns(new HttpCookieCollection());
        Request.Setup(x => x.QueryString).Returns(new NameValueCollection());
        Request.Setup(x => x.Form).Returns(new NameValueCollection());

        // Apply the mock context to the supplied controller instance
        RequestContext rc = new RequestContext(HttpContext.Object, new RouteData());
        onController.ControllerContext = new ControllerContext(rc, onController);
        onController.Url = new UrlHelper(rc);
    }

    ContextMocks() {
    }

    // Use a fake HttpSessionStateBase, because it's hard to mock it with Moq
    private class FakeSessionState : HttpSessionStateBase {
        Dictionary<string, object> items = new Dictionary<string, object>();
        public override object this[string name] {
            get { return items.ContainsKey(name) ? items[name] : null; }
            set { items[name] = value; }
        }
    }
}

}

答案 1 :(得分:2)

您引用的代码解释了如何伪造httpcontext - 当您调用“hb.Session.Add”时它实际上没有做任何事情 - 它只是因为依赖于HttpContext而停止测试失败。 / p>

答案 2 :(得分:1)

您可以使用Outercurve Foundation提供的MVC Contrib库来模拟会话状态和处理正常请求期间可用的其他对象(HttpRequest,HttpResponse等)。

http://mvccontrib.codeplex.com/(或使用NuGet下载)

它包含TestHelper library,可帮助您快速创建单元测试。

例如:

[TestMethod]
public void TestSomething()
{
    TestControllerBuilder builder = new TestControllerBuilder();

    // Arrange
    HomeController controller = new HomeController();

    builder.InitializeController(controller);

    // Act
    ViewResult result = controller.About() as ViewResult;

    // Assert
    Assert.IsNotNull(result);
}

使用MVC Contrib TestHelper库提供的TestControllerBuilder类型,您可以快速初始化控制器并初始化其内部数据成员(HttpContext,HttpSession,TempData ...)。

当然,HttpSessionState本身也是这样嘲笑的,所以添加一些东西(Session.Add)实际上不会做什么。按照预期,我们嘲笑它。

好像你想要模拟HttpContext,但仍然设置了一个工作会话状态。听起来你想要做一些如下所述的事情:

http://jasonbock.net/jb/Default.aspx?blog=entry.161daabc728842aca6f329d87c81cfcb

答案 3 :(得分:1)

这就是我通常做的事情

//Mock The Sesssion
_session = MockRepository.GenerateStrictMock<httpsessionstatebase>();
_session.Stub(s => s["Connectionstring"]).Return(Connectionstring);

//Mock The Context 
_context = MockRepository.GenerateStrictMock<httpcontextbase>();
_context.Stub(c => c.Session).Return(_session);

var databaseExplorerController = new DatabaseExplorerController(repository);

//Assign COntext to controller
databaseExplorerController.ControllerContext = new ControllerContext(_context, new RouteData(),
                                                                     _databaseExplorer);

我在

写了一篇关于此的小文章

http://www.gigawebsolution.com/Posts/Details/66/Mock-Session-in-MVC3-using-Rhino-Mock

希望这有帮助

答案 4 :(得分:0)

有点晚了,但这是有用的。

我正在使用https://code.google.com/p/moq/

中的MoQ框架

现在会话在控制器实现中可用。

    private class MockHttpSession : HttpSessionStateBase
    {
        readonly Dictionary<string, object> _sessionDictionary = new Dictionary<string, object>();
        public override object this[string name]
        {
            get
            {
                object obj = null;
                _sessionDictionary.TryGetValue(name, out obj);
                return obj;
            }
            set { _sessionDictionary[name] = value; }
        }
    }

    private ControllerContext CreateMockedControllerContext()
    {
        var session = new MockHttpSession();
        var controllerContext = new Mock<ControllerContext>();
        controllerContext.Setup(m => m.HttpContext.Session).Returns(session);

        return controllerContext.Object;
    }

    [TestMethod]
    public void Index()
    {
        // Arrange
        MyController controller = new MyController();
        controller.ControllerContext = CreateMockedControllerContext(); 

        // Act
        ViewResult result = controller.Index() as ViewResult;

        ....
    }