单元测试代码,它依赖于一个依赖于HttpContext.Current的SessionManager类

时间:2012-09-14 19:19:32

标签: 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)
    {
        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);
        }
    }
}

在我的HomeController中,我有以下代码:

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

    // commented for brevity

    return View("Index");
}

当我对Landing方法运行单元测试时,测试失败,因为HttpContext.Current为null。我在单元测试中模拟了Session对象,如果我尝试直接在Landing方法中访问Session(即Session [“SomeValue”]),它可以工作,但任何依赖于SessionManager的代码都会被破坏。

底线是我想要一个类,我可以使用它以通用的强类型方式访问Session值,但也可以进行单元测试。任何人都有关于如何修改此代码以实现此目的的任何建议?

3 个答案:

答案 0 :(得分:1)

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

或者,将SessionManager类本身设为非static,并使HttpContextBase作为构造函数参数。

一般情况下,永远不要使用HttpContext.Current。如果您希望您的代码可以测试或可重用。

答案 1 :(得分:0)

您只能通过引入另一个抽象层来使其可测试。这是你自己的IOurHttpContext和OurDotNetHttpContext:用于真实app的IOurHttpContext和用于测试的OurTestHttpContext:IOutHttpContext(后者不需要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; }
}
很容易。但它可能很复杂。

答案 2 :(得分:0)

您可以将HttpContext.Current设置为_httpContext