简体   繁体   English

依赖于SessionManager类并依赖于HttpContext.Current的单元测试代码

[英]Unit testing code that relies on a SessionManager class with a dependency on HttpContext.Current

I have a SessionManager class in an existing application that looks like this: 我在现有应用程序中有一个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);
        }
    }
}

In my HomeController, I have code like the following: 在我的HomeController中,我有如下代码:

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

    // commented for brevity

    return View("Index");
}

When I run a unit test on the Landing method, the test fails because HttpContext.Current is null. 当我对Landing方法运行单元测试时,测试失败,因为HttpContext.Current为null。 I've mocked the Session object in my unit tests, and if I attempt to access Session directly in the Landing method (ie Session["SomeValue"]) it works, but any code that relies on the SessionManager is broken. 我已经在单元测试中模拟了Session对象,并且如果我尝试直接通过Landing方法(即Session [“ SomeValue”])访问Session,它可以工作,但是任何依赖SessionManager的代码都被破坏了。

Bottom line is that I want a class I can use to access Session values in a generic, strongly typed manner, but that can also be unit tested. 最重要的是,我希望我可以使用一个类以通用的强类型方式访问Session值,但是也可以对该单元进行测试。 Anyone have any suggestions on how I can modify this code to achieve that? 任何人都对如何修改此代码以实现该目标有任何建议?

If you've already mocked the Session in your test's HttpContextBase, all you need to do is change SessionManager to accept your custom HttpContextBase (eg, in a [ThreadStatic] field) 如果您已经在测试的HttpContextBase中模拟了Session,则只需更改SessionManager即可接受自定义HttpContextBase(例如,在[ThreadStatic]字段中)

Alternatively, make the SessionManager class itself non- static , and make it take an HttpContextBase as a constructor parameter. 或者,使SessionManager类本身为非static类,并使其以HttpContextBase作为构造函数参数。

In general, you should never use HttpContext.Current . 通常,永远不要使用HttpContext.Current if you want your code to be testable or reusable. 如果您希望代码可测试或可重用。

You can only make it testable by introducing another abstraction layer. 您只能通过引入另一个抽象层来使其可测试。 That is your own IOurHttpContext and OurDotNetHttpContext : IOurHttpContext for real app and OurTestHttpContext : IOutHttpContext for tests (the latter not needed with moq). 那是您自己的IOurHttpContext和OurDotNetHttpContext:用于实际应用程序的IOurHttpContext,以及用于测试的OurTestHttpContext:IOutHttpContext(moq不需要后者)。 OurDotNetHttpContext may look like: 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; }
}

pretty easy. 相当容易。 It may be mo sophisticated though. 虽然可能会很复杂。

您可以将HttpContext.Current设置为_httpContext

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM