2009-04-20 6 views
57

würde Ich magWie man frühere Erwartungen an ein Objekt löscht? in einem bestimmten Test

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

aber dann einen Rückgabewert einzurichten, diese Erwartung außer Kraft setzen false zurück.

Etwas wie:

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

Hinweis, ich auf dem zweiten Aufruf falsch zurück nicht die Erwartung, ich will die erste Erwartung außer Kraft zu setzen.

Dies würde helfen, mein Testszenario erheblich zu vereinfachen.

Antwort

67

Es gibt drei Möglichkeiten:

Sie können die Erwartungen zurück, indem BackToRecord mit

Ich muss zugeben, dass ich nie benutzt es wirklich, weil es peinlich ist.

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

Edit: Jetzt habe ich es verwenden, manchmal ist es tatsächlich der sauberste Weg. Es sollte eine Erweiterungsmethode (wie Stub) geben, die es tut - ich glaube, es wurde einfach vergessen. Ich würde vorschlagen, dass Sie Ihre eigenen schreiben.

Sie können Repeat.Any (verwenden)

Es bricht "die Reihenfolge der Stub Definition und "überschreibt" vorherige Definitionen. Aber es ist irgendwie implizit. Ich benutze es manchmal, weil es einfach zu schreiben ist.

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

Sie können einen neuen Mock erstellen

Trivial, aber eindeutige und leicht zu verstehen. Es ist nur ein Problem, wenn Sie viele Definitionen behalten und nur einen Anruf ändern möchten.

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

In internen Rhino Mock sprechen, mit Wiederholen. Jeder erzeugt eine wiederholbare Erwartung, die bei der Wiedergabe normale Erwartungen übertrifft. Ich empfehle jedoch, BackToRecord zu verwenden. –

+0

Ah, ich habe alles außer dem Aufruf von Replay() herausgefunden. –

+1

Dies ist eine Sache, die nur von Menschen bekannt ist, die RhinoMocks seit 3.4 oder älter benutzen. RhinoMocks arbeitete mit Record-Replay, das bedeutet, dass ein Mock explizit in den Replay-Modus gesetzt werden musste. Mit 3,5, zum Glück ist das weg, Mocks sind immer im Replay-Modus (zumindest für den benutzerdefinierten Code). Bis Sie es in den Aufnahmemodus zurückversetzen - außer dass Sie die Erwartungen klären, sehe ich keinen Grund, dies zu tun. Ich wollte bereits einen Patch für diese beiden Zeilen schreiben, um die Erwartungen bequem zurückzusetzen. –

22

Für diese Situationen habe ich eine einfache Methode RinoMocks Erweiterung besser die Absicht des Stutzens zu zeigen und die Lesbarkeit zu fördern.

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

Anstatt also ein kryptischer Aufruf wie folgt aus, das einen Kommentar erfordern:

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

Sie können einen besser lesbaren Test erhalten, dass ein besseres zeigt die Absicht der .Repeat.Any() Anrufe :

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

Um die Option offen zu halten, um die Stub-Konfiguration zu verketten, sollte die Erweiterungsmethode keine IMethodOptions zurückgeben? 'public static IMethodOptions OverridePrevious (diese IMethodOptions Optionen) {return options.Repeat.Any(); } '. – PHeiberg

+2

@PHeiberg - Ich habe es nicht versucht oder hatte die Notwendigkeit, die Kette offen zu halten, aber ja, ich nehme an, Sie haben Recht. Guter Punkt. – MoMo

+0

Ich mag OverridePrevious als void - es zwingt es bis zum Ende. – user2864740

5

aus Gründen der Gemeinde oben ich werde dies in der Stefans Liste der Optionen hinzuzufügen:

Wenn der Rückgabewert häufig geändert werden muss, finde ich es sauber und effizient, einen Verschluss wie folgt zu verwenden.

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; 

Der Lambda-Ausdruck wird jedes Mal Contains ausgeführt werden aufgerufen und weil wir eine Schließung erstellt Referenzierung returnValue, es wird immer die aktuellen Wert von returnValue nachzuschlagen.

+0

Dies ist meiner Meinung nach die sauberste Lösung –

Verwandte Themen