2008-11-13 4 views
28

Ich möchte bestätigen, dass eine Methode genau einmal aufgerufen wird. Ich benutze RhinoMocks 3.5.Asserting, dass eine Methode genau einmal aufgerufen wird

Hier ist, was ich dachte funktionieren würde:

[Test] 
public void just_once() 
{ 
    var key = "id_of_something"; 

    var source = MockRepository.GenerateStub<ISomeDataSource>(); 
    source.Expect(x => x.GetSomethingThatTakesALotOfResources(key)) 
     .Return(new Something()) 
     .Repeat.Once(); 

    var client = new Client(soure); 

    // the first call I expect the client to use the source 
    client.GetMeMyThing(key); 

    // the second call the result should be cached 
    // and source is not used 
    client.GetMeMyThing(key); 
} 

ich diesen Test, wenn der zweite Aufruf von GetMeMyThing() Anrufe source.GetSomethingThatTakesALotOfResources() scheitern wollen.

Antwort

32

So würde ich überprüfen, ob eine Methode einmal aufgerufen wird.

[Test] 
public void just_once() 
{ 
    // Arrange 
    var a = MockRepository.GenerateMock<ISomeDataSource>(); 
    a.Expect(x => x.GetSomethingThatTakesALotOfResources()).Return(new Something()).Repeat.Once(); 
    a.Stub(x => x.GetSomethingThatTakesALotOfResources()).Throw(new InvalidOperationException("gotcha")); 

    // Act 
    // First invocation should call GetSomethingThatTakesALotOfResources 
    a.GetMeMyThing(); 

    // Second invocation should return cached result 
    a.GetMeMyThing(); 

    // Assert 
    a.VerifyAllExpectations(); 
} 
+1

+1 für die Verwendung von 'using (mocks.Record()) {..} Es erhöht die Lesbarkeit sehr. –

+0

-1 Dies funktioniert nicht. Es wird keine Ausnahme ausgelöst, wenn GetSomethingThatTakesALotOfResources mehr als einmal aufgerufen wird. – Ergwun

+0

Ich bin mir ziemlich sicher, dass das zu der Zeit funktionierte, als ich das vor 2 Jahren schrieb. Ich werde den Beitrag aktualisieren, um die neue Vorgehensweise zu integrieren. –

2

Hier ist was ich gerade getan habe (wie von Ray Houston empfohlen). Ich würde immer noch eine elegantere Lösung zu schätzen wissen ...

[Test] 
public void just_once() 
{ 
    var key = "id_of_something"; 

    var source = MockRepository.GenerateStub<ISomeDataSource>(); 

    // set a positive expectation 
    source.Expect(x => x.GetSomethingThatTakesALotOfResources(key)) 
     .Return(new Something()) 
     .Repeat.Once(); 

    var client = new Client(soure); 

    client.GetMeMyThing(key); 

    // set a negative expectation 
    source.Expect(x => x.GetSomethingThatTakesALotOfResources(key)) 
     .Return(new Something()) 
     .Repeat.Never(); 

    client.GetMeMyThing(key); 
} 
+0

Dies würde nur funktionieren, wenn Ihr Aufrufcode auf einem ausreichend hohen Niveau war, dass Sie Zugriff auf die wiederholte Methode hatten. In meinem Fall rufe ich in 1 Methode auf, in der 2 Anrufe innerhalb dieser Methode gemacht werden, also kann ich den Anruf innerhalb des Testkörpers nicht wiederholen. Ich habe es trotzdem probiert, aber das Never() überschreibt das Once einfach und ich bekomme nur Expect 1 bekommen 0 – PandaWood

4

Sie können in this bit vom Rhino Mocks 3.5 Dokumentation (zitiert unten) interessiert sein. Sieht so aus, als müsstest du die Klasse verspotten, nicht stubben, damit sie so funktioniert, wie du es erwartest.

Der Unterschied zwischen Stubs und spottet

...

Ein Mock ist ein Objekt, das wir Erwartungen auf, und die überprüfen wird festlegen, dass die erwarteten Aktionen haben in der Tat aufgetreten. Ein Stub ist ein Objekt, das Sie verwenden, um den Code unter testen zu können. Sie können Erwartungen auf es einrichten, so würde es auf bestimmte Arten, handeln, aber diese Erwartungen werden nie verifiziert werden. Die Eigenschaften eines Stubs verhalten sich automatisch wie normale Eigenschaften und Sie können keine Erwartungen an sie setzen.

Wenn Sie das Verhalten von der im Test befindlichen Code überprüfen mögen, erhalten Sie einen Mock mit der entsprechenden Erwartung verwenden, und überprüfen. Wenn Sie nur einen Wert übergeben möchten, der in einer bestimmten Art und Weise handeln muss, aber nicht der Fokus von auf diesen Test ist, verwenden Sie einen Stub.

WICHTIG: Ein Stub führt niemals dazu, dass ein Test fehlschlägt.

-1

eine Funktion namens „Genau“ Nachdem wäre praktisch Tests, Code zu schreiben, die sonst in eine Endlosschleife bekommen könnte. Ich würde gerne einen Test schreiben, bei dem der zweite Aufruf einer Methode eine Ausnahme auslösen würde.

Einige Bibliotheken für Python ermöglichen es Ihnen, Erwartungen zu sequenzieren, so dass die erste falsch zurückgibt und die zweite eine Ausnahme auslöst.

Rhino wird das nicht tun. Ein partieller Schein mit .Once wird den ersten Aufruf abfangen, und der Rest wird an die ursprüngliche Methode weitergegeben. Also das ist scheiße, aber es ist wahr.

Sie müssen einen Hand-Mock erstellen. Leiten Sie eine "testbare" Klasse ab und geben Sie ihr die Möglichkeit, nach dem ersten Aufruf zu erhöhen.

15

Ich habe die AssertWasCalled-Erweiterung verwendet, um dieses Problem zu umgehen. Dies ist das Beste, was ich finden konnte, aber es wäre besser, wenn ich den Anruf nicht zweimal angeben müsste.

[Test] 
    public void just_once() 
    { 
     var key = "id_of_something"; 

     var source = MockRepository.GenerateStub<ISomeDataSource>(); 

     // set a positive expectation 
     source.Expect(x => x.GetSomethingThatTakesALotOfResources(key)) 
      .Return(new Something()) 
      .Repeat.Once(); 

     var client = new Client(soure); 
     client.GetMeMyThing(key); 
     client.GetMeMyThing(key); 

     source.AssertWasCalled(x => x.GetSomethingThatTakesALotOfResources(key), 
           x => x.Repeat.Once()); 
     source.VerifyAllExpectations(); 
    } 
+0

Danke, die einzige Antwort, die für mich funktioniert hat. Ein Unterschied für mich war, dass interne Exceptions (nullref) zu vermeiden und sicherzustellen, dass ich stattdessen eine nette Rhino Expectation Ausnahme hatte, musste ich Repeat.Twice(), um über den Fall "Fail" zu bekommen. Deshalb ist diese Lösung gut, das ist egal, die AssertWasCalled definiert genau, was benötigt wird. – PandaWood

+1

Was macht der 'Excpect'? Ich glaube nicht, dass 'VerifyAllExpectations' auf einem Stub funktioniert, es funktioniert nur auf einem Mock. Aber selbst wenn es funktionieren würde, was nützt es? Ihr 'AssertWasCalled' enthält alle erforderlichen Assertions. Ich würde 'Expect' in' Stub' ändern und die 'Repeat.Once' ablegen und auch die' VerifyAllExpectations' entfernen. – comecme

2

Sie können einen Delegaten WhenCalled passieren Anrufe zählen:

... 
uint callCount = 0; 
source.Expect(x => x.GetSomethingThatTakesALotOfResources(key)) 
    .Return(new Something()) 
    .WhenCalled((y) => { callCount++; }); 
... 
Assert.AreEqual(1, callCount); 

Auch sollten Sie ein Modell verwenden kein Stummel, und auch die Erwartungen an die Mock überprüfen.

0

Sie können strict mock erstellen, wenn Sie sicherstellen möchten, dass eine Methode nur einmal aufgerufen wird.

var mock = MockRepository.GenerateStrictMock<IMustOnlyBeCalledOnce>(); 
mock.Expect(a => a.Process()).Repeat.Once(); 
var helloWorld= new HelloWorld(mock); 

helloworld.Process() 

mock.VerifyAllExpectations(); 
Verwandte Themen