在遗留的ASP.NET应用程序中进行单元测试以模拟HttpContext

时间:2016-04-28 06:38:18

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

我有一个方法:

public DataSet someMethod()
{
    List a = someObj.getList(name, integerId);
}

现在,通过HttpContext.Current.Session变量获取integerId。 我已经为该方法编写了一个单元测试。但是,因为测试在Web进程之外运行,HttpContext.Current.Session返回null并且测试失败。

有没有解决方法呢?

3 个答案:

答案 0 :(得分:1)

首先,您必须初始化HttpContext.Current

HttpContext.Current = new HttpContext(new HttpRequest("", "http://blabla.com", "") {},
                                      new HttpResponse(new StringWriter()));

然后你必须设置会话:( Necroskillz在his blog中解释了这样做的方法)

public static void SetFakeSession(this HttpContext httpContext)
{
    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 });
}

以下代码段显示了它的工作原理:

[TestMethod]
public void TestMethod1()
{
    HttpContext.Current = new HttpContext(new HttpRequest("", "http://blabla.com", "") {},
                                          new HttpResponse(new StringWriter()));

    HttpContext.Current.SetFakeSession();

    HttpContext.Current.Session["foo"] = 1;

    Assert.AreEqual(1, HttpContext.Current.Session["foo"]);
}

答案 1 :(得分:1)

我想这个问题的懒惰答案是:学会使用dependency injection,但我会继续提供一些指示。

类不太可能在HttpContext中需要所有。您没有指定计算integerId的方式,但让我们说它是当前SessionState的{​​{1}}的哈希值。您的所有课程实际上都需要某种方式来获取特定的SessionId ;这不需要是一个完整的SessionId

HttpContext

现在你的班级有:

interface ICurrentSessionIdProvider
{
     string SessionId { get; }
}

现在在你的单元测试中,模拟这种依赖变得微不足道。像Moq和AutoFixture这样的工具甚至会为你做这件事,现在你的生活很轻松愉快等等。

当然,在实际应用程序中,您希望使用基于HttpContext的实现:

// Pull this from a constructor parameter so you can provide any implementation you want
private readonly ICurrentSessionIdProvider _sessionIdProvider;

public DataSet someMethod()
{
     int integerId = _sessionIdProvider.SessionId.GetHashCode();
     List a = someObj.getList(name, integerId);
}

答案 2 :(得分:0)

您需要以某种方式为您的测试注入假HttpContext - 理想情况下为HttpContextBase,这是一个可模拟但相同的API。

您可以将HttpContext包裹在HttpContextWrapper中以获得HttpContextBase

阅读有关控制反转的各种技术,并找到适合您的技术。