2009-04-20 7 views
57

Je voudrais mettre en place une valeur de retourComment effacer les attentes précédentes sur un objet?

_stubRepository.Stub(Contains(null)).IgnoreArguments().Return(true); 

mais dans un test spécifique, passer outre cette attente de retourner faux.

Quelque chose comme:

_stubRepository.ClearExpectations(); //<- this does not exist, I'm just making something up 
_stubRepository.Stub(Contains(null)).IgnoreArguments().Return(false); 

avis, je ne veux pas l'attente de revenir faux sur le deuxième appel, je veux remplacer la première attente.

Ceci aiderait grandement à simplifier mon scénario de test.

Répondre

67

Il existe trois façons:

Vous pouvez réinitialiser les attentes en utilisant BackToRecord

Je dois admettre que je jamais vraiment utilisé parce qu'il est maladroit.

// clear expectations, an enum defines which 
_stubRepository.BackToRecord(BackToRecordOptions.All); 
// go to replay again. 
_stubRepository.Replay(); 

Edit: Maintenant je l'utilise parfois, il est en fait la manière la plus propre. Il devrait y avoir une méthode d'extension (comme Stub) qui le fait - je pense que c'est juste oublié. Je suggérerais d'écrire le vôtre.

Vous pouvez utiliser Repeat.Any()

Il brise l'ordre de la définition et bouchonné « préséances » définitions précédentes. Mais c'est en quelque sorte implicite. Je l'utilise parfois parce que c'est facile à écrire.

_stubRepository.Stub(x => x.Contains(null)) 
    .IgnoreArguments() 
    .Return(false) 
    .Repeat.Any(); 

Vous pouvez créer une nouvelle maquette

Trivial, mais explicite et facile à comprendre. C'est seulement un problème si vous voulez garder beaucoup de définitions et ne changer qu'un appel.

_stubRepository = MockRepository.GenerateMock<IRepository>(); 
_stubRepository.Stub(x => x.Contains(null)) 
    .IgnoreArguments() 
    .Return(false); 
+0

En interne Rhino Mock parle, en utilisant Repeat. Tout crée une attente répétable, qui surpasse les attentes normales pendant la lecture. Je recommande d'utiliser BackToRecord, cependant. –

+0

Ah, tout compris, sauf pour l'appel Replay(). –

+1

Ceci est une chose que seuls les gens utilisant RhinoMocks connaissent depuis 3.4 ou plus. RhinoMocks a travaillé avec Record-Replay, ce qui signifie qu'une simulation doit être explicitement configurée en mode Replay. Avec 3,5, heureusement que cela a disparu, les mocks sont toujours en mode replay (au moins pour le code personnalisé). Jusqu'à ce que vous reveniez en mode d'enregistrement - sauf pour effacer les attentes, je ne vois aucune raison de le faire. Je voulais déjà écrire un patch pour ces deux lignes pour réinitialiser confortablement les attentes. –

22

Pour ces situations, je créé une méthode simple extention RinoMocks pour mieux montrer l'intention de la souche et promouvoir la lisibilité.

public static void OverridePrevious<T>(this IMethodOptions<T> options) 
{ 
    options.Repeat.Any(); 
} 

Ainsi, au lieu d'un appel cryptique comme suit qui peut nécessiter un commentaire:

[SetUp] 
public void Setup() 
{ 
    carStub.Stub(x => x.Model).Return("Model1"); 
    carStub.Stub(x => x.Model).Return("Model2"); 
} 

[Test] 
public void SomeTest() 
{ 
    //Arrange 
    //overrides previous stubs that were setup for the Model property 
    carStub.Stub(x => x.Model).Return(null).Repeat.Any(); 

    //Act 
    //Assert 
} 

Vous pouvez obtenir un test plus lisible que montre mieux l'intention des appels .Repeat.Any() :

carStub.Stub(x => x.Model).Return(null).OverridePrevious(); 
+5

Afin de garder l'option ouverte à la chaîne de la configuration de talon, la méthode d'extension ne devrait pas renvoyer un IMethodOptions ? 'public IMethodOptions OverridePrevious (cette IMethodOptions options) {return options.Repeat.Any(); } '. – PHeiberg

+2

@PHeiberg - Je ne l'ai pas essayé ou j'avais besoin de garder la 'chaîne ouverte' mais oui je suppose que vous avez raison. Bon point. – MoMo

+0

J'aime OverridePrevious comme void - il l'oblige à la fin. – user2864740

5

au nom de la communauté, je vais ajouter ceci à ajouter à la liste des options de Stefan ci-dessus:

Si la valeur de retour doit être changée fréquemment, je trouve qu'il est propre et efficace d'utiliser une fermeture comme suit.

bool returnValue = true; 
_stubRepository.Stub(x => x.Contains(null)).IgnoreArguments().Do(new Func<bool>(() => { 
    return returnValue; 
})); 

returnValue = false; 
// Calls to Contains now return false; 

returnValue = true; 
// Calls to Contains now return true; 

L'expression lambda sera exécutée chaque fois que Contains est appelé et parce que nous avons créé une référence à la fermeture returnValue, il regardera toujours la valeur actuelle de returnValue.

+0

C'est la solution la plus propre à mon avis –