C# 依赖于SessionManager类且依赖于HttpContext.Current的单元测试代码

C# 依赖于SessionManager类且依赖于HttpContext.Current的单元测试代码,c#,unit-testing,session,httpcontext,C#,Unit Testing,Session,Httpcontext,我在一个现有应用程序中有一个SessionManager类,如下所示: public class SessionManagerBase<TKey> { public static void AddItem(TKey key, object item) { _httpContext.Session[key.ToString()] = item; } public static T GetItem<T>(TKey key)

我在一个现有应用程序中有一个SessionManager类,如下所示:

public class SessionManagerBase<TKey>
{
    public static void AddItem(TKey key, object item)
    {
        _httpContext.Session[key.ToString()] = item;
    }

    public static T GetItem<T>(TKey key)
    {
        object item = _httpContext.Session[key.ToString()];
        return item == null ? default(T) : (T) Convert.ChangeType(item, typeof (T));
    }

    // etc...

    private static HttpContextBase _httpContext
    {
        get
        {
            return new HttpContextWrapper(HttpContext.Current);
        }
    }
}
公共类SessionManagerBase
{
公共静态无效附加项(TKey,对象项)
{
_httpContext.Session[key.ToString()]=项;
}
公共静态T GetItem(TKey)
{
对象项=_httpContext.Session[key.ToString()];
returnitem==null?默认值(T):(T)Convert.ChangeType(item,typeof(T));
}
//等等。。。
私有静态HttpContextBase\u httpContext
{
得到
{
返回新的HttpContextWrapper(HttpContext.Current);
}
}
}
在我的HomeController中,我有如下代码:

public ActionResult Landing(string id)
{
    SessionManager.GetItem<Campaign>(SessionKeys.Campaign)

    // commented for brevity

    return View("Index");
}
公共操作结果登录(字符串id)
{
SessionManager.GetItem(SessionKeys.Campaign)
//简明扼要
返回视图(“索引”);
}
当我在Landing方法上运行单元测试时,测试失败,因为HttpContext.Current为null。我在单元测试中模拟了Session对象,如果我试图在Landing方法中直接访问Session(即Session[“SomeValue”]),它会工作,但依赖SessionManager的任何代码都会被破坏


底线是我想要一个类,我可以用它以一种通用的、强类型的方式访问会话值,但它也可以进行单元测试。有人对我如何修改此代码以实现这一点有什么建议吗?

如果您已经在测试的HttpContextBase中模拟了会话,那么您需要做的就是更改SessionManager以接受自定义HttpContextBase(例如,在
[ThreadStatic]
字段中)

或者,将
SessionManager
类本身设置为非静态的
static
,并将
HttpContextBase
作为构造函数参数


通常,您不应该使用
HttpContext.Current
。如果您希望您的代码是可测试的或可重用的。

您只能通过引入另一个抽象层使其可测试。这是您自己的IOurHttpContext和我们的DotNetHttpContext:IOurHttpContext(用于real app)和我们的TestHttpContext:IOuthtpContext(用于测试,moq不需要后者)。OurDotNetHttpContext可能看起来像:

public interface IOutHttpContext {
    object GetSessionVar( string key );
    void SetSessionVar( string key, object value );
}
public class OurDotNetHttpContext : IOutHttpContext {
    public object GetSessionVar(string key) { return HttpContext.Current.Session[key]; }
    public void SetSessionVar(string key, object value) { HttpContext.Current.Session[key] = value; }
}

很简单。不过它可能非常复杂。

您可以将HttpContext.Current设置为您的_HttpContext