我有一个web服务,我试图单元测试。在服务中,它从HttpContext中提取了几个值,如下所示:

 m_password = (string)HttpContext.Current.Session["CustomerId"];
 m_userID = (string)HttpContext.Current.Session["CustomerUrl"];

在单元测试中,我使用一个简单的工作请求创建上下文,如下所示:

SimpleWorkerRequest request = new SimpleWorkerRequest("", "", "", null, new StringWriter());
HttpContext context = new HttpContext(request);
HttpContext.Current = context;

然而,每当我试图设置HttpContext.Current.Session的值时

HttpContext.Current.Session["CustomerId"] = "customer1";
HttpContext.Current.Session["CustomerUrl"] = "customer1Url";

我得到空引用异常,说HttpContext.Current.Session是空的。

是否有方法在单元测试中初始化当前会话?


当前回答

你可以通过创建一个新的HttpContext来“伪造”它,就像这样:

http://www.necronet.org/archive/2010/07/28/unit-testing-code-that-uses-httpcontext-current-session.aspx

我把这段代码放到一个静态helper类中,如下所示:

public static HttpContext FakeHttpContext()
{
    var httpRequest = new HttpRequest("", "http://example.com/", "");
    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);

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

    return httpContext;
}

或者不是使用反射来构造新的httpessionstate实例,你可以将你的httpessionstatecontainer附加到HttpContext(根据Brent M. Spell的评论):

SessionStateUtility.AddHttpSessionStateToContext(httpContext, sessionContainer);

然后你可以像这样在单元测试中调用它:

HttpContext.Current = MockHelper.FakeHttpContext();

其他回答

我之前写过一些关于这方面的东西。

单元测试MVC3 .NET中的HttpContext.Current.Session

希望能有所帮助。

[TestInitialize]
public void TestSetup()
{
    // We need to setup the Current HTTP Context as follows:            
 
    // Step 1: Setup the HTTP Request
    var httpRequest = new HttpRequest("", "http://localhost/", "");
 
    // Step 2: Setup the HTTP Response
    var httpResponce = new HttpResponse(new StringWriter());
 
    // Step 3: Setup the Http Context
    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 });
 
    // Step 4: Assign the Context
    HttpContext.Current = httpContext;
}

[TestMethod]
public void BasicTest_Push_Item_Into_Session()
{
    // Arrange
    var itemValue = "RandomItemValue";
    var itemKey = "RandomItemKey";
             
    // Act
    HttpContext.Current.Session.Add(itemKey, itemValue);
             
    // Assert
    Assert.AreEqual(HttpContext.Current.Session[itemKey], itemValue);
}

如果您正在使用MVC框架,这应该可以工作。我使用Milox的FakeHttpContext并添加了一些额外的代码行。这个想法来自这个帖子:

http://codepaste.net/p269t8

这似乎在MVC 5中工作。我还没有尝试在早期版本的MVC。

HttpContext.Current = MockHttpContext.FakeHttpContext();

var wrapper = new HttpContextWrapper(HttpContext.Current);

MyController controller = new MyController();
controller.ControllerContext = new ControllerContext(wrapper, new RouteData(), controller);

string result = controller.MyMethod();

我找到了以下在HttpContext中指定用户的简单解决方案:https://forums.asp.net/post/5828182.aspx

你可以通过创建一个新的HttpContext来“伪造”它,就像这样:

http://www.necronet.org/archive/2010/07/28/unit-testing-code-that-uses-httpcontext-current-session.aspx

我把这段代码放到一个静态helper类中,如下所示:

public static HttpContext FakeHttpContext()
{
    var httpRequest = new HttpRequest("", "http://example.com/", "");
    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);

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

    return httpContext;
}

或者不是使用反射来构造新的httpessionstate实例,你可以将你的httpessionstatecontainer附加到HttpContext(根据Brent M. Spell的评论):

SessionStateUtility.AddHttpSessionStateToContext(httpContext, sessionContainer);

然后你可以像这样在单元测试中调用它:

HttpContext.Current = MockHelper.FakeHttpContext();

@Ro Hit给出的答案对我帮助很大,但我缺少用户凭据,因为我必须伪造一个用户进行身份验证单元测试。因此,让我描述一下我是如何解决它的。

根据此,如果添加方法

    // using System.Security.Principal;
    GenericPrincipal FakeUser(string userName)
    {
        var fakeIdentity = new GenericIdentity(userName);
        var principal = new GenericPrincipal(fakeIdentity, null);
        return principal;
    }

然后追加

    HttpContext.Current.User = FakeUser("myDomain\\myUser");

到TestSetup方法的最后一行就完成了,添加用户凭据并准备用于身份验证测试。

我还注意到HttpContext中还有其他你可能需要的部分,比如. mappath()方法。这里有一个可用的FakeHttpContext,它可以通过NuGet安装。