Que faut-il dans HttpContext pour permettre à FormsAuthentication.SignOut () de s'exécuter?

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

  •  07-07-2019
  •  | 
  •  

Question

J'essaie d'écrire un test unitaire pour notre méthode de déconnexion. Entre autres choses, il FormsAuthentication.SignOut () . Cependant, il génère une System.NullReferenceException .

J'ai créé une maquette; HttpContext (en utilisant Moq), mais il manque évidemment quelque chose.

Mon contexte factice contient:

  • Un HttpRequestBase simulé sur la demande
  • Un HttpResponseBase fictif sur Réponse
  • Avec une HttpCookieCollection sur Request.Cookies et une autre sur Response.Cookies
  • Un IPrincipal fictif sur Utilisateur

Je sais que je pourrais aller dans la route du wrapper et injecter un objet wrapper FormsAuth vide à sa place, mais je voudrais vraiment éviter les 3 fichiers supplémentaires simplement pour corriger une ligne de code. Cela et je suis toujours curieux de réponse

Ma question est donc " Ce qui est nécessaire dans HttpContext pour permettre à FormsAuthentication.SignOut () de s'exécuter. "

Était-ce utile?

La solution

Voici le code pour la fermeture de session.

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

On dirait que vous avez besoin d'une instance CookielessHelperClass. Dommage que ce soit interne et scellé - il n'y a aucun moyen de s'en moquer sauf si vous utilisez TypeMock. +1 pour les suggestions d'emballage:)

Autres conseils

L'exception NullReferenceException dans ce cas est en réalité levée par l'appel:

current.Request.Browser["supportsEmptyStringInCookieValue"]

Vous pouvez tester cette assertion en appelant:

HttpContext.Current.Request.Browser.SupportsEmptyStringInCookieValue

... qui renverra également l'exception NullReferenceException. Contrairement à la réponse acceptée, si vous essayez d'appeler:

CookielessHelperClass.UseCookieless(current, false, CookieMode)

... dans la fenêtre immédiate, cela renverra sans erreur.

Vous pouvez corriger l'exception de la manière suivante:

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

... et l'appel FormsAuthentication.SignOut () aboutira à présent.

Vous pouvez toujours envelopper FormsAuthentication.SignOut () dans une autre méthode et le stub / mock.

Créer une interface IFormsAuthenticationWrap.

public interface IFormsAuthenticationWrap
{
    void SignOut();
}

Créer une classe wrap qui implémente IFormsAuthenticationWrap

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

Votre classe d'appel va ressembler à ceci:

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

Maintenant passons à notre test. Vous pouvez écraser Moque avec Moq mais je vais montrer ici comment vous pouvez le faire manuellement. Créez votre classe de stub / mock:

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

Et le dernier écrit le test:

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

Le wrapper est la solution idéale.

Vous avez mentionné dans un commentaire que "cela va être une très grosse application", c’est un autre argument pour utiliser le wrapper et non l’inverse. Dans une grande application, vous voulez des dépendances claires et des tests faciles à effectuer.

Vous échangez des dépendances propres qui peuvent facilement être injectées par-dessus des dépendances obscures du fonctionnement interne de asp.net dans vos tests.

Sur une note différente: Utiliser le réflecteur . Honnêtement, je ne connais pas les dépendances internes de cette partie spécifique de asp.net, mais vous pouvez dissiper tout doute avec un réflecteur.

Ne vous moquez pas de HttpContext, utilisez-en un réel dans vos tests. De cette façon, vous ne devez pas vous moquer de tous ces trucs Http *. Vous pouvez utiliser Ivonna et tester votre méthode directement, sans se moquer de toutes ces dépendances et obtenir des exceptions mystérieuses.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top