如何为单元测试设置UserLanguages(使用模拟的http上下文)?

时间:2015-04-13 08:16:17

标签: asp.net unit-testing httpcontext

我正在为asp.net应用程序进行单元测试。由于我目前正在测试的类是如何设计的,它使用多个线程,因此手动设置其中一个线程的语言:

Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(HttpContext.Current.Request.UserLanguages[0]);

为了实现这一点,我在运行包含上述代码的类之前,通过在单元测试中使用以下类来模拟httpcontext:

public class HttpContextMock
{
    public static HttpContext MockedHttpContext()
    {
        var httpRequest = new HttpRequest("", "MyUrl", "");
        var stringWriter = new StringWriter();
        var httpResponse = new HttpResponse(stringWriter);
        var httpContext = new HttpContext(httpRequest, httpResponse);

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

        return httpContext;
    }

现在问题是即使我得到一个有效的httpcontext命令

HttpContext.Current.Request.UserLanguages

始终返回null。

所以我的问题是为了确保UserLanguages至少返回1个条目可以做些什么?

1 个答案:

答案 0 :(得分:0)

当您刚刚发现时,模拟出HTTPContext并不容易。

为什么不完全避免这种情况?

而不是

Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(HttpContext.Current.Request.UserLanguages[0]);

您可以执行类似

的操作
Thread.CurrentThread.CurrentUICulture = _ContextSpecificSettings.Language;

_ContextSpecificSettings是您自己编码的类的实例。可能是这样的:

class ContextSpecificSettings
{
    HTTPContext _HTTPContext;

    public ContextSpecificSettings()
    {
        _HTTPContext = HTTPContext;
    }

    public string Language // used string but you would of course use here whatever type is used in UserLanguages
    { 
        get { return _HttpContext.Current.Request.UserLanguages[0]; } 
    }
}

现在,您只需要模拟/存根自己的ContextSpecificSettings类,而不是尝试模拟HTTPContext。这样做要容易得多,因为你需要模拟/存根才能返回你想要在测试中使用的语言。

剩下要做的就是确保包含Thread.CurrentThread.CurrentUICulture分配的类能够获得ContextSpecificSettings类的实例。您可以使用简单的构造函数注入来实现。例如:

class SomeThreadUsingClass
{
    ContextSpecificSettings _Settings;

    public SomeThreadContextUsingClass(ContextSpecificSettings useThisSettingsInstance)
    {
        _Settings = useThisSettingsInstance;
    }

    public Int SomeMethodUsingLanguage()
    {
        // <snip>
        Thread.CurrentThread.CurrentUICulture = _Settings.Language;
        // <snip>
        return Whatever;
    }
}

在实际代码中实例化SomeThreadUsingClass时,将其传递给ContextSpecificSettings类的(新)实例。在测试中实例化SomeThreadUsingClass时,您所要做的就是将一个实例传递给ContextSpecificSettings Mock / Stub类。

顺便说一句,这与我在Property.Settings.Default makes it hard to unit test any method that uses it

中描述的技术相同