2010-02-10 3 views
1

J'ai converti certaines anciennes spécifications en MSpec (utilisaient NUnit/SpecUnit). Les spécifications sont pour un modèle de vue, et le modèle de vue en question effectue une vérification de sécurité personnalisée. Nous avons une méthode d'assistance dans nos spécifications qui configurera de fausses informations de sécurité pour Thread.CurrentPrincipal. Cela a bien fonctionné dans les anciens tests unitaires, mais échoue dans MSpec. Plus précisément, je reçois cette exception:Comment écrire des spécifications avec MSpec pour du code qui change Thread.CurrentPrincipal?

"System.Runtime.Serialization.SerializationException: Type is not resolved for member"

Il se produit quand une partie de la SUT essaie de lire le fichier de configuration de l'application. Si je commente la ligne qui définit le CurrentPrincipal (ou l'appelle simplement après la partie qui vérifie le fichier de configuration), l'erreur disparaît, mais les tests échouent en raison du manque d'informations d'identification.

De même, si je définissez CurrentPrincipal sur null, l'erreur disparaît, mais à nouveau les tests échouent car les informations d'identification ne sont pas définies. J'ai googlé ceci, et j'ai trouvé des articles sur la façon de s'assurer que le principal personnalisé est sérialisable lorsqu'il franchit les limites de AppDomain (généralement en référence aux applications web). Dans notre cas, ce n'est pas une application web, et je ne traverse aucun AppDomains. Notre objet pincipal est également sérialisable.

J'ai téléchargé la source pour MSpec, et trouvé que le ConsoleRunner appelle une classe nommée AppDomainRunner. Je ne l'ai pas débogué dedans, mais il semble qu'il exécute les spécifications dans différents domaines d'application.

Alors, est-ce que quelqu'un a des idées sur la façon dont je peux surmonter cela? J'aime vraiment MSpec, et j'aimerais l'utiliser exclusivement. Mais je dois être en mesure de fournir de fausses informations de sécurité lors de l'exécution des tests.

Voici la classe de spécification:

[Subject(typeof(CountryPickerViewModel))] 
public class When_the_user_makes_a_selection : PickerViewModelSpecsBase 
{ 
    protected static CountryPickerViewModel picker; 

    Establish context =() => 
    { 
     SetupFakeSecurityCredentials(); 
     CreateFactoryStubs(); 

     StubLookupServicer<ICountryLookupServicer>() 
      .WithData(BuildActiveItems(new [] { "USA", "UK" })); 

     picker = new CountryPickerViewModel(ViewFactory, ViewModelFactory, 
           BusinessLogicFactory, CacheFactory); 

    }; 

    Because of =() => 
     picker.SelectedItem = picker.Items[0]; 

    Behaves_like<Picker_that_has_a_selected_item> a_picker_with_a_selection; 
} 

Nous avons un certain nombre de ces modèles de vue « picker », tous présentent des comportements communs. Donc j'utilise la fonctionnalité Behaviors de MSpec. Cette classe particulière simule l'utilisateur sélectionnant quelque chose du contrôle (WPF) qui est lié à cette machine virtuelle. La méthode SetupFakeSecurityCredentials() définit simplement Thread.CurrentPrincipal sur une instance de notre principal personnalisé, où le composant a été renseigné pour les droits d'accès complet.

est ici un faux CountryPickerViewModel qui est suffisant pour provoquer l'erreur:

public class CountryPickerViewModel 
{ 
    public CountryPickerViewModel(IViewFactory viewFactory, 
       IViewModelFactory viewModelFactory, 
       ICoreBusinessLogicFactory businessLogicFactory, 
       ICacheFactory cacheFactory) 
    { 
     Items = new Collection<int>(); 
     var validator = ValidationFactory.CreateValidator<object>(); 
    } 

    public int SelectedItem { get; set; } 
    public Collection<int> Items { get; private set; } 

} 

Il est l'appel ValidationFactory qui explose. ValidationFactory est un objet Bibliothèque d'entreprise qui tente d'accéder à la configuration.

+0

Dan, pourriez-vous s'il vous plaît publier un exemple de code pour nous aider à déboguer le comportement que vous décrivez? Oui, les tests sont exécutés dans des domaines d'application distincts de sorte que le fichier .config de la DLL soit détecté par vos spécifications. Ensuite, la définition de Thread.CurrentPrincipal et la lecture des valeurs de app.config dans vos tests me semblent être une odeur. C'est un comportement qui devrait résider dans des classes séparées qui sont faciles à remplacer dans les spécifications de votre modèle de vue. –

+0

Alexander, j'ai mis à jour avec le code de spécification. Je suis d'accord avec tes deux points sur les odeurs. Nous sommes préoccupés par l'injection du code qui effectue réellement les contrôles de sécurité, car un appelant pourrait facilement faire la même chose (avec sa propre implémentation), et ainsi contourner notre sécurité. D'un autre côté, ils pourraient théoriquement aussi simuler les identifiants sur le fil de la même manière que nous sommes dans les tests. Je ne sais pas quelle est la meilleure approche. En ce qui concerne l'accès à la configuration, cela est en fait effectué par la bibliothèque d'entreprise. C'est un tout autre sujet. :) –

Répondre

Questions connexes