【问题标题】:Issue with writing a Unit Test for HttpContext.Current.Session为 HttpContext.Current.Session 编写单元测试的问题
【发布时间】:2015-03-16 14:09:08
【问题描述】:

我有一个工作应用程序,现在我需要为其添加一整套单元测试。当前代码存储用户信息如下:

HttpContext.Current.Session["UserInfo"] = userData;

我使用 moq 进行测试,我的单元测试有以下代码:

var server = new Mock<HttpServerUtilityBase>(MockBehavior.Loose);
var response = new Mock<HttpResponseBase>(MockBehavior.Strict);
var request = new Mock<HttpRequestBase>(MockBehavior.Strict);

var context = new Mock<HttpContextBase>();

context.SetupGet(x => x.Request).Returns(request.Object);
context.SetupGet(x => x.Response).Returns(response.Object);
context.SetupGet(x => x.Server).Returns(server.Object);

var controller = new LoginController();

controller.ControllerContext = new ControllerContext(
    context.Object, 
    new RouteData(), 
    controller);

JsonResult result = controller.LoginUser(
    new LoginHelper { 
        userName = "myusername", 
        password = "invalidpassword" 
        }
    ) as JsonResult;

当然,当我到达登录进程尝试创建会话数据的位置时,我得到一个“未设置对象实例的对象引用”。错误,因为 HttpContext.Current 为空。

一些研究表明,使用 Current 与 MSTest 并不完全兼容,因此我知道我可能需要更改存储/加载用户信息的方式。不过,我想就去这里的方式提出一些建议。

如果有任何关于如何让我的单元测试正常工作或存储用户信息以使其与单元测试更兼容的不同方法的建议,我将不胜感激。

【问题讨论】:

  • 在 ASP.Net MVC 应用程序中使用 HttpContext.Current 很奇怪,但是您可以简单地将 HttpContext.Current 设置为您的模拟上下文(创建这样的上下文完全是另一回事,所以 :))...您确实应该考虑使用 MVC 方式访问上下文或将整个会话包装到接口中并依赖于该接口,而不是直接访问 HttpContext.Current
  • @AlexeiLevenkov 如果使用 HttpContext.Current 很奇怪,还有什么替代方案?
  • 另一种方法是将 SessionStateBase 注入控制器,而不是从 HttpContext 中获取。

标签: c# asp.net-mvc unit-testing moq mstest


【解决方案1】:

这是我想出的解决方案。这是我在不同地方找到的一些东西的组合,包括这里:

首先,我创建了 2 个类 .. MockHttpSession 和 MockHelpers

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; }
    }

    public override void Abandon()
    {
        // Do nothing
    }
}

public class MockHelpers
{
    public static HttpContext FakeHttpContext()
    {
        var httpRequest = new HttpRequest("", "http://localhost/", "");
        var stringWriter = new StringWriter();
        var httpResponse = new HttpResponse(stringWriter);
        var httpContext = new HttpContext(httpRequest, httpResponse);

        var sessionContainer = new HttpSessionStateContainer(
            "id", 
            new SessionStateItemCollection(),
            new HttpStaticObjectsCollection(), 
            10, 
            true,
            HttpCookieMode.AutoDetect,
            SessionStateMode.InProc, 
            false);

        SessionStateUtility.AddHttpSessionStateToContext(httpContext, sessionContainer);

        return httpContext;
    }
}

然后我更改了我的单元测试代码以使用这些:

var server = new Mock<HttpServerUtilityBase>(MockBehavior.Loose);
var response = new Mock<HttpResponseBase>(MockBehavior.Strict);
var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
var session = new MockHttpSession();

var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);
context.SetupGet(x => x.Response).Returns(response.Object);
context.SetupGet(x => x.Server).Returns(server.Object);
context.SetupGet(x => x.Session).Returns(session);

HttpContext.Current = MockHelpers.FakeHttpContext();

var controller = new LoginController();
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);

JsonResult result = controller.LoginUser(new LoginHelper { userName = "MyUserName", password = ""InvalidPassword }) as JsonResult;

这能够成功地测试密码有效和无效的代码。

感谢大家的帮助

【讨论】:

    猜你喜欢
    • 2012-11-13
    • 2012-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-16
    • 1970-01-01
    相关资源
    最近更新 更多