0

我在现有应用程序中有一个 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 为空。我在单元测试中模拟了 Session 对象,如果我尝试直接在 Landing 方法中访问 Session(即 Session["SomeValue"]),它可以工作,但是任何依赖 SessionManager 的代码都会被破坏。

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

4

3 回答 3

1

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

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

一般来说,你永远不应该使用HttpContext.Current. 如果您希望您的代码可测试或可重用。

于 2012-09-14T19:22:17.303 回答
0

您只能通过引入另一个抽象层来使其可测试。那是您自己的 IOurHttpContext 和 OurDotNetHttpContext : 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; }
}

挺容易。虽然它可能更复杂。

于 2012-09-14T19:33:12.733 回答
0

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

于 2012-09-14T23:05:06.357 回答