在模拟请求时,ASP.NET MVC,HttpContext.Current为null

时间:2015-04-18 09:17:16

标签: asp.net-mvc unit-testing session mocking nunit

public async Task <ActionResult>Select(DWorkingTimeSelection dto) { 
    var session = HttpUtils.GetSeesion<User>("USER"); 
} 

public static T GetSeesion<T>(string key) where T : class
{ 
    if (HttpContext.Current == null) 
    { 
        return default(T);
    }
     return HttpContext.Current.Session[key] as T; 
}

public async Task <ActionResult>Select(DWorkingTimeSelection dto) { 
    var session = HttpUtils.GetSeesion<User>("USER"); 
} 

public static T GetSeesion<T>(string key) where T : class
{ 
    if (HttpContext.Current == null) 
    { 
        return default(T);
    } 
    return HttpContext.Current.Session[key] as T; 
}

我使用nunti来模拟请求。 我将SessionStateItemCollection添加到Controller的ControllerContext中。 我发现HttpContext.Current是null但是Controller的Session [] 不是null,因为它来自Controller的ControllerContext。 那么在模拟请求时我该怎么做才能避免HttpContext.Current为null

2 个答案:

答案 0 :(得分:1)

你可以模拟HttpContext:

    public static HttpContext FakeHttpContext(HttpRequest request)
    {
        var stringWriter = new StringWriter();
        var httpResponce = new HttpResponse(stringWriter);
        var httpContext = new HttpContext(request, 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;
    }

    [TestMethod]
    public void ActionTest()
    {
        var request = new HttpRequest(string.Empty, "url to the action that you are testing", string.Empty)
        {
            RequestType = "GET"
        };
        HttpContext.Current = FakeHttpContext(request);

        var controller = new YourController();
        //You need the get a Result property since it is an async action
        var result = controller.ActionToTest(//the parameters that your action expects).Result;
        Assert.IsNotNull(result);
    }

编辑(回答评论中的问题)

要获得会话,您需要致电HttpContext.Current.Session而不是HttpContext.Current.Session["id"],因为HttpContext.Current.Session["id"]会尝试从您的会话中获取id密钥。 一旦你将它存储在那里,它将通过这个电话可用。你可以测试一下:

HttpContext.Current.Session["id"] = 5;
Assert.AreEqual(HttpContext.Current.Session["id"],5);

关于httpContext.Items声明:

(来自MSDN)HttpContext.Items是一个键/值集合,可用于在HTTP请求期间在IHttpModule接口和IHttpHandler接口之间组织和共享数据。

您要求的语句,只是通过使用反射来创建一个新的HttpSessionState对象(因为它只有内部构造函数)将它与您之前创建的HttpSessionStateContainer相关联并将其存储在{在HttpContext.Items下{1}}。有趣的是AspSession实际上是HttpContext.Current.Session的捷径。因此,将HttpSessionState对象赋值给HttpContext.Items["AspSession"]键是使AspSession起作用的基础。

答案 1 :(得分:1)

好吧,在嘲笑HttpContext后,Alex Art说道。

调用以下方法即可。

var sessionItems = new SessionStateItemCollection();
        sessionItems["SessionKey"] = new MyCustomObject();
        SessionStateUtility.AddHttpSessionStateToContext(fakeHttpContext,
            new HttpSessionStateContainer(SessionNameStorage.Suser,
                          sessionItems,
                          new HttpStaticObjectsCollection(),
                          20000,
                          true,
                          HttpCookieMode.AutoDetect,
                          SessionStateMode.InProc,
                          false
                      ));