2009-07-22 9 views
1

Je suis actuellement en train de refactoriser du code qui exécute Windows Impersonation pour testabilité et qui s'est heurté à un peu d'un roadblock. Ceci est le bit de code que j'ai des problèmes avec:Mocking l'instanciation d'un objet pour un test unitaire

... 
if (LogonUserA(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) > 0) 
{ 
    if (DuplicateToken(token, 2, ref tokenDuplicate)) 
    { 
     var tempWindowsIdentity = new System.Security.Principal.WindowsIdentity(tokenDuplicate); 
     var impersonationContext = tempWindowsIdentity.Impersonate(); 
     ... 
    } 
... 
} 

Comment puis-je me moque le comportement de l'instanciation d'un objet WindowsIdentity sur? J'ai pensé à diverses alternatives:

  • passe dans une classe d'usine qui créerait l'instance et se moquer du comportement de cette
  • Pass un délégué qui gère la création de l'instance (par exemple comme un pointeur de fonction C++)

Aucune de ces alternatives semblent particulièrement bon pour moi parce que je crains qu'ils brouillerait l'intention de la méthode que la signature de la méthode ressemblerait à quelque chose comme ce qui suit:

public bool Impersonate(string user, string password, string domain, Factory factory) 

ou

public bool Impersonate(string user, string password, string domain, delegate WinIDCreator) 

Parce que l'objectif de la méthode consiste à usurper l'identité d'un utilisateur particulier, il ne me fait pas sens que ce soit une classe d'usine ou délégué devraient lui être communiqués. Je veux isoler et mocker ce comportement cependant comme je suis mal à l'aise avec la pensée d'une nouvelle instance de WindowsIdentity étant créée chaque fois que je cours un tas de tests unitaires.

Des idées ou des commentaires?

Répondre

4

Je pense que vous êtes sur la bonne voie avec l'idée d'usine, mais j'Injecter le usine dans le constructeur de classe non comme un paramètre de méthode. Votre constructeur par défaut peut créer une instance de Factory par défaut si elle n'est pas fournie.

Vous aurez également quelques problèmes - comme l'utilisation de véritables identifiants de connexion et de mots de passe dans vos tests unitaires - si vous ne prenez pas en compte les méthodes LogonUserA et DuplicateToken. Je suggère une enveloppe fine autour de cette implémentation d'une interface que vous pouvez également injecter dans le constructeur. Ci-dessous, quelques-uns des points forts pour vous montrer comment commencer à structurer.

public interface ILogonHelpers 
{ 
    bool LogonUser(string user, string domain, string password, ref int token); 
    void DuplicateToken( int token, ref int duplicateToken); 
} 

public class MyClass 
{ 
    public MyClass(ILogonHelper logonHelper, IIdentityFactory factory) 
    { 
     this.LogonHelper = logonHelper ?? new DefaultLogonHelper(); 
     this.IdentityFactory = factory ?? new DefaultIdentityFactory(); 
    } 

    ... 

if (this.LogonHelper.Logon(user, domain, password, ref token) > 0) 
{ 
    if (this.LogonHelper.DuplicateToken(token, ref tokenDuplicate)) 
    { 
     var tempWindowsIdentity = this.IdentityFactory.CreateIdentity(tokenDuplicate); 
     var impersonationContext = tempWindowsIdentity.Impersonate(); 
     ... 
    } 
... 
} 
+0

Merci pour cela. J'aurais dû ajouter que j'ai encapsulé les choses de connexion dans une classe NativeMethods et je me moque simplement de celles-ci. L'inquiétude que j'ai avec l'injection de l'usine dans la classe est la même que l'utilisation comme une méthode param - il ne semble pas «naturel» d'avoir une classe qui dépend d'une usine de classe ... – jpoh

+0

ie Cette classe effectue L'emprunt d'identité et donc il a une dépendance sur une classe NativeMethods (qui encapsule les choses de l'API Win dont j'ai besoin). Je trouve difficile de me convaincre que le fait d'avoir aussi une dépendance sur une classe Factory est OK. – jpoh

0

Je voudrais créer une méthode virtuelle d'emprunt d'identité que vous pourriez simuler. La méthode de Impersonate serait la suivante:


public virtual WindowsImpersonationContext Impersonate(string tokenDuplicate) { 
    var tempWindowsIdentity = new System.Security.Principal.WindowsIdentity(tokenDuplicate); 
    var impersonationContext = tempWindowsIdentity.Impersonate(); 

    return impersonationContext; 
} 
1

Je suis un dev Java mais ...

Pourquoi ne pas faire la « Factory » un attribut de la classe qui contient la méthode Impersonate? L'attribut "Factory", peut-être "windowIdentityFactory", peut être défini dans le constructeur ou via une méthode setter (en utilisant un type d'injection de dépendance).

Le test, vous fournissez à la classe une simulation d'usine (comme vous l'avez suggéré). En production, vous lui donnez la vraie affaire.

... 
if (LogonUserA(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) > 0) 
{ 
    if (DuplicateToken(token, 2, ref tokenDuplicate)) 
    { 
     var tempWindowsIdentity = windowIdentityFactory.newInstance(tokenDuplicate); 
     var impersonationContext = tempWindowsIdentity.Impersonate(); 
     ... 
    } 
... 
} 
0

Je suis d'accord avec tvanfosson au sujet de l'injection de l'usine par le constructeur (ou peut-être par une propriété si vous considériez l'usine en option). Cependant, puisque vous n'êtes pas très heureux à ce sujet, je vous suggère de jeter un oeil à TypeMock Isolator, ce qui vous permettra de simuler des instances d'une manière plutôt non conventionnelle. Il fonctionne en injectant IL de la même manière que les profileurs et il vous permet d'utiliser des mock sans modifier vos configurations d'objet.

Questions connexes