如何使用Moq模拟会话对象集合

ray*_*030 44 tdd asp.net-mvc unit-testing moq

我正在使用shanselmann的MvcMockHelper类来使用Moq模拟一些HttpContext的东西,但我遇到的问题是能够在我的MVC控制器中为我的模拟会话对象分配一些东西,然后能够在我的单元测试中读取相同的值以进行验证目的.

我的问题是如何将存储集合分配给模拟的会话对象,以允许诸如session ["UserName"] ="foo"之类的代码保留"foo"值并使其在单元测试中可用.

Ron*_*ack 63

我从Scott Hanselman的MVCMockHelper开始,添加了一个小类并进行了如下所示的修改,以允许控制器正常使用Session和单元测试来验证控制器设置的值.

/// <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"]);
Run Code Online (Sandbox Code Playgroud)

它并不完美,但它足以进行测试.

  • 感谢您提供此示例,它非常有用。我稍微修改了您的 MockHttpSession 以返回 null 而不是在字典中不存在键时抛出异常以更接近地模拟 HttpSession 对象。只是给其他消费者的一个提示。 (2认同)

Tod*_*ith 35

在这里使用Moq 3.0.308.2是我的单元测试中的帐户控制器设置示例:

    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;
    }
Run Code Online (Sandbox Code Playgroud)

然后在你的控制器方法中,以下应返回"Hello World"

string test = Session["test"].ToString ();
Run Code Online (Sandbox Code Playgroud)