Подтвердить что ты не робот

Что нужно в HttpContext для выполнения FormsAuthentication.SignOut()?

Я пытаюсь написать unit test для нашего метода выхода. Среди прочего это FormsAuthentication.SignOut(). Однако он выбрасывает System.NullReferenceException.

Я создал макет; HttpContext (используя Moq), но, очевидно, чего-то не хватает.

Мой макет содержит:

  • Издевается HttpRequestBase на Request
  • Издевается HttpResponseBase на Response
  • С HttpCookieCollection на Request.Cookies, а другой на Response.Cookies
  • Издевается IPrincipal на User

Мне известно, что я мог бы пойти по маршруту обертки и ввести пустой объект FormsAuth в этом месте, но мне бы очень хотелось избежать 3 дополнительных файлов, чтобы исправить одну строку кода. Это и я все еще интересуюсь ответом

Итак, мой вопрос: " Что необходимо в HttpContext, чтобы разрешить FormsAuthentication.SignOut() to execute."

4b9b3361

Ответ 1

Вот код для выписки.

public static void SignOut()
{
    Initialize();
    HttpContext current = HttpContext.Current;
    bool flag = current.CookielessHelper.DoesCookieValueExistInOriginal('F');
    current.CookielessHelper.SetCookieValue('F', null);
    if (!CookielessHelperClass.UseCookieless(current, false, CookieMode) || current.Request.Browser.Cookies)
    {
        string str = string.Empty;
        if (current.Request.Browser["supportsEmptyStringInCookieValue"] == "false")
        {
            str = "NoCookie";
        }
        HttpCookie cookie = new HttpCookie(FormsCookieName, str);
        cookie.HttpOnly = true;
        cookie.Path = _FormsCookiePath;
        cookie.Expires = new DateTime(0x7cf, 10, 12);
        cookie.Secure = _RequireSSL;
        if (_CookieDomain != null)
        {
            cookie.Domain = _CookieDomain;
        }
        current.Response.Cookies.RemoveCookie(FormsCookieName);
        current.Response.Cookies.Add(cookie);
    }
    if (flag)
    {
        current.Response.Redirect(GetLoginPage(null), false);
    }
}

Похоже, вам нужен экземпляр CookielessHelperClass. Жаль, что это внутреннее и запечатанное - нет способа издеваться над ним, если вы не используете TypeMock. +1 для предложений обложки:)

Ответ 2

Исключение NullReferenceException в этом случае фактически вызывается вызовом:

current.Request.Browser["supportsEmptyStringInCookieValue"]

Вы можете проверить это утверждение, вызвав:

HttpContext.Current.Request.Browser.SupportsEmptyStringInCookieValue

... который также вернет исключение NullReferenceException. Вопреки принятому ответу, если вы попытаетесь позвонить:

CookielessHelperClass.UseCookieless(current, false, CookieMode)

... из непосредственного окна, это вернется без ошибок.

Исправление можно исправить следующим образом:

HttpContext.Current.Request.Browser = new HttpBrowserCapabilities() { Capabilities = new Dictionary<string, string> { { "supportsEmptyStringInCookieValue", "false" } } };

... и вызов FormsAuthentication.SignOut() теперь будет успешным.

Ответ 3

Вы всегда можете перенести FormsAuthentication.SignOut() в другой метод и заглушить/издеваться над ним.

Создайте интерфейс IFormsAuthenticationWrap.

public interface IFormsAuthenticationWrap
{
    void SignOut();
}

Создайте класс переноса, который реализует IFormsAuthenticationWrap

public class FormsAuthenticationWrap : IFormsAuthenticationWrap
{
    public void SignOut()
    {
        FormsAuthentication.SignOut();
    }
}

Ваш вызывающий класс будет выглядеть примерно так:

public class LogOutClass
{
    private readonly IFormsAuthenticationWrap _formsAuthentication;

    public LogOutClass() : this (new FormsAuthenticationWrap())
    {
    }

    public LogOutClass(IFormsAuthenticationWrap formsAuthentication)
    {
        _formsAuthentication = formsAuthentication;
    }

    public void LogOutMethod()
    {
        // Code before SignOut

        _formsAuthentication.SignOut();

        // Code after SignOut
    }
}

Теперь перейдем к нашему тесту. Вы можете заглушить/издеваться над Moq, но я собираюсь показать здесь, как вы можете сделать это вручную. Создайте класс заглушки/макета:

public class FormsAuthenticationStub : IFormsAuthenticationWrap
{
    public void SignOut()
    {
    }
}

И последний напишет тест:

    [TestMethod]
    public void TestLogOutMethod()
    {
        var logOutClass = new LogOutClass(new FormsAuthenticationStub());
        logOutClass.LogOutMethod();
    }

Ответ 4

Обертка - это чистый путь.

Вы упомянули в комментарии, что "это будет довольно большое приложение", это еще один аргумент, чтобы использовать обертку не наоборот. В большом приложении вы хотите иметь четкие зависимости, и вы хотите, чтобы тесты выполнялись легко.

Вы торгуете чистыми зависимостями, которые можно легко вводить по неясным зависимостям во внутренние действия asp.net в ваших тестах.


В другом примечании: Использовать рефлектор. Я честно не знаю внутренних зависимостей этой конкретной части asp.net, но вы можете устранить любые сомнения с помощью отражателя.

Ответ 5

Не издевайтесь над HttpContext, используйте реальный тест. Таким образом, вам не нужно издеваться над всеми этими материалами Http *. Вы можете использовать Ivonna и протестировать свой метод напрямую, не издеваясь над всеми этими зависимостями и получая загадочные исключения.