2016-04-28 145 views
2

我有一个方法:单元测试嘲笑HttpContext的

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

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

对此有什么解决办法?

+1

嘲讽的HttpContext是在经典的ASP.NET中很难。我建议你在自己的可模拟类中包装你对HttpContext.Session的引用。 – Joe

+0

数据访问层不应该依赖于HttpContext对象。 – izsl

+0

是的,理想情况下应该是这样。但是,为了遵循这一点,我的项目中的大量代码将不得不被重新考虑。 –

回答

0

你需要为你的测试注入一个假的HttpContext - 最好是HttpContextBase,这是一个可嘲弄的,但在其他方面相同的API。

你可以将HttpContext换成HttpContextWrapper得到HttpContextBase

有一个关于控制反转的各种技术阅读起来,找到一个适合您。

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

我猜拉兹Ÿ这个问题的答案是:学会使用dependency injection,但我会继续前进,并提供一些指针。

这是不太可能的类需要一切在HttpContext的。你不指定如何计算你integerId,但让我们说这是当前SessionStateSessionId的哈希值。您的所有类实际上需要的是办法让特定SessionId;这并不需要是一个完整的HttpContext

interface ICurrentSessionIdProvider 
{ 
    string SessionId { get; } 
} 

现在你的类有:

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

现在,在你的单元测试就变得微不足道嘲笑这种依赖性。像起订量和AutoFixture工具甚至会为你做它,现在你的生活是轻松和快乐等

当然,在你想使用基于HttpContext的一个实现的实际应用:

class HttpContextCurrentSessionIdProvider : ICurrentSessionIdProvider 
{ 
    // Pull this from a constructor parameter or however you see fit. 
    private readonly HttpContext _httpContext; 

    public SessionId => _httpContext.Current.Session.SessionId; 
}