O que é necessário no HttpContext para permitir FormsAuthentication.SignOut () para executar?

StackOverflow https://stackoverflow.com/questions/1430180

  •  07-07-2019
  •  | 
  •  

Pergunta

Eu estou tentando escrever um teste de unidade para o nosso log out método. Entre outras coisas, FormsAuthentication.SignOut(). No entanto, ele lança um System.NullReferenceException.

Eu criei um mock; HttpContext (usando Moq), mas é, obviamente, faltando alguma coisa.

O meu contexto simulado contém:

  • A HttpRequestBase ridicularizado em Request
  • A HttpResponseBase ridicularizado em Response
  • Com um HttpCookieCollection em Request.Cookies e outro sobre Response.Cookies
  • A IPrincipal ridicularizado em User

Estou ciente de que eu poderia ir a rota invólucro e injetar um FormsAuth vazio invólucro objeto em seu lugar, mas eu realmente gostaria de evitar os 3 arquivos adicionais apenas para corrigir uma linha de código. Isso e eu ainda estou curioso por uma resposta

Então, minha pergunta é " O que é necessário no HttpContext para permitir FormsAuthentication.SignOut() to execute. "

Foi útil?

Solução

Aqui está o código para signout.

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

Parece que você precisa de uma instância CookielessHelperClass. Pena que é interna e selado - não há nenhuma maneira de zombar-lo a menos que você estiver usando TypeMock. +1 para sugestões de mensagens publicitárias:)

Outras dicas

O NullReferenceException neste caso realmente está sendo jogado pela chamada:

current.Request.Browser["supportsEmptyStringInCookieValue"]

Você pode testar esta afirmação chamando:

HttpContext.Current.Request.Browser.SupportsEmptyStringInCookieValue

... que também irá retornar o NullReferenceException. Ao contrário do que a resposta aceita, se você tentar chamar:

CookielessHelperClass.UseCookieless(current, false, CookieMode)

... a partir da janela imediata, isso irá retornar sem erro.

Você pode corrigir a exceção como este:

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

... ea chamada FormsAuthentication.SignOut() agora vai ter sucesso.

Você pode sempre envolver FormsAuthentication.SignOut () em outro método e ramal / zombar-lo.

Criar a interface IFormsAuthenticationWrap.

public interface IFormsAuthenticationWrap
{
    void SignOut();
}

Criar classe envoltório que implementos IFormsAuthenticationWrap

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

Sua classe chamando vai ser algo como isto:

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

Agora vamos chegar ao nosso teste. Você pode stub / simulada com Moq mas eu vou mostrar aqui como você pode fazê-lo manualmente. Criar seu esboço de classe / simulação:

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

E a última gravação do teste:

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

O invólucro é a maneira limpa para ir.

Você mencionou em um comentário que "este vai ser um grande aplicação", que é um outro argumento para utilizar o wrapper não o contrário. Em um grande aplicativo que deseja ter dependências claras, e você quer testes para ser feito facilmente.

Você está negociando dependências limpas que podem ser facilmente injetados sobre dependências obscuras para o funcionamento interno do asp.net em seus testes.


Em uma nota diferente: Use Refletor . Eu honestamente não sei as dependências internas desta parte específica do asp.net, mas você pode esclarecer dúvidas com refletor.

Não zombe HttpContext, use um real em seus testes. Desta forma, você não tem que zombam de todas estas Http * coisas. Você pode usar Ivonna e testar seu método diretamente, sem zombando de todas estas dependências e recebendo exceções misteriosas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top