【问题标题】:Session null in unit test单元测试中的会话为空
【发布时间】:2018-04-30 08:46:28
【问题描述】:

我正在尝试为相当基本的控制器操作编写一些单元测试,其中我设置了 Session["User"]。当我运行测试时,此时它失败并出现空引用异常。不完全确定如何解决这个问题。

控制器:

public ActionResult Index(int id)
        {
            Session["User"] = Id;

            if (Id != 0)
            {
                return RedirectToAction("Home", "Home", new { Id});
            }

            return RedirectToAction("Register", "Home", new { Id});
        }

测试:

[TestMethod]
        public void NewUser_ShouldGoToRegister()
        {
            var controller = new HomeController();

            HttpContext.Current = FakeHttpContext();

            HttpContext.Current.Session.Add("User", "0");

            var result = controller.Index(0) as ViewResult;

            Assert.AreEqual("Register", result.ViewName);
        }


        public HttpContext FakeHttpContext()
        {
            var httpRequest = new HttpRequest("", "http://localhost/", "");

            var httpResponce = new HttpResponse(new StringWriter());

            var httpContext = new HttpContext(httpRequest, httpResponce);
            var sessionContainer =
                new HttpSessionStateContainer("id",
                                               new SessionStateItemCollection(),
                                               new HttpStaticObjectsCollection(),
                                               10,
                                               true,
                                               HttpCookieMode.AutoDetect,
                                               SessionStateMode.InProc,
                                               false);
            httpContext.Items["AspSession"] =
                typeof(HttpSessionState)
                .GetConstructor(
                                    BindingFlags.NonPublic | BindingFlags.Instance,
                                    null,
                                    CallingConventions.Standard,
                                    new[] { typeof(HttpSessionStateContainer) },
                                    null)
                .Invoke(new object[] { sessionContainer });


            HttpContext.Current = httpContext;
        }

【问题讨论】:

  • 您需要阅读有关模拟 Web 对象(例如 HttpContext、HttpRequest 等)的内容。基本上从一开始就阅读有关单元测试控制器代码的内容。
  • 我有一个 [TestInitialize] 方法可以设置类似的东西
  • 我们怎么知道你做了那件事以及你在那里犯了什么错误?请分享代码。
  • 非常抱歉。我更新了代码以包含它。原本打算这样做

标签: c# asp.net-mvc unit-testing session httpcontext


【解决方案1】:

您可以使用MOQ 等模拟工具进行模拟,创建假的HttpContext 您可以尝试如下代码。

[TestMethod]
public void NewUser_ShouldGoToRegister()
{
    var controller = new HomeController();
    HttpContext.Current = FakeHttpContext();
    HttpContext.Current.Session.Add("User", 1);
    var result = controller.Index(0) as ViewResult;
    Assert.AreEqual("Register", result.ViewName);
}

您的FakeHttpContext 方法应类似于以下代码。

        //Creating a Fake HTTP Context           
        // This is used for testing methods using Session Variables.
        private HttpContext FakeHttpContext()
        {
            var httpRequest = new HttpRequest("", "http://somethig.com/", "");
            var stringWriter = new StringWriter();
            var httpResponce = new HttpResponse(stringWriter);
            var httpContext = new HttpContext(httpRequest, httpResponce);

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

            httpContext.Items["AspSession"] = 
                typeof(HttpSessionState).GetConstructor(
                                        BindingFlags.NonPublic | BindingFlags.Instance,
                                        null, CallingConventions.Standard,
                                        new[] { typeof(HttpSessionStateContainer) },
                                        null)
                                .Invoke(new object[] { sessionContainer });

            return httpContext;
        }

【讨论】:

  • 我刚刚尝试过使用这种方法,但当我调试它时仍然得到一个空会话。有什么想法吗?
  • 仍然为空。它肯定在测试中设置了会话,但是当它通过控制器时它是空的
  • 我看过那个问题但没有成功:/
  • 这很奇怪,它总是对我有用。你能检查一下会话密钥吗,你正在尝试访问你正在添加的那个?
【解决方案2】:

如果您对此有困难,这个想法可能会帮助您过度思考。有时创建对Session 的另一层访问权限是个好主意。

一种简化的方法是永远不要直接访问“会话”,而是将其包装到这样的方法中:

protected virtual string ReadFromSession(string key)
{
    return Session[key];
}

protected virtual void StoreInSession(string key, string value)
{
    Session[key] = value;
}

在 Controller 的任何地方,您只需使用这些方法,而不是直接访问 Session。很简单。

现在的诀窍是使用单元测试,您可以覆盖您测试的控制器:

public class MyControllerForTesting : MyController
{
    private readonly IDictionary session;

    public MyControllerForTesting(IDictionary session) : base()
    {
        this.session = session;
    }

    protected override string ReadFromSession(string key)
    {
        return this.session[key];
    }

    protected override void StoreInSession(string key, string value)
    {
        this.session[key] = value;
    }
}

现在这可能不会立即起作用,因为我没有真正测试它,但你明白了。您的单元测试有效,如果值设置正确等,您甚至可以检查字典。

【讨论】:

    猜你喜欢
    • 2013-05-14
    • 2011-09-26
    • 1970-01-01
    • 2012-09-21
    • 2013-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-07
    相关资源
    最近更新 更多