2011-12-28 8 views
10

E 'possibile testare il seguente esempio se il Metodo 1 chiamato 1st, poi Method2 chiamato dopo e poi Method3 usando la sintassi AAA, in Rhino-mocks 3.6?Posso verificare l'ordine di chiamata del metodo con la sintassi AAA in Rhino-Mocks 3.6?

// Assert 
var mock = MockRepository.GenerateMock<ISomeService>(); 

// Act 
myObject.Service = mock; 

// How should I change this part to ensure that Rhino Mocks check the call order as well? 
mock.AssertWasCalled(m=>m.Method1()); 
mock.AssertWasCalled(m=>m.Method2()); 
mock.AssertWasCalled(m=>m.Method3()); 

risposta

19

Ecco un modo per farlo ...

mock.AssertWasCalled(m=>m.Method1(), options => options.WhenCalled(w => mockService.AssertWasNotCalled(x=>x.Method2()))); 
mock.AssertWasCalled(m=>m.Method2(), options => options.WhenCalled(w => mockService.AssertWasNotCalled(x=>x.Method3()))); 
mock.AssertWasCalled(m=>m.Method3()); 
8

È possibile, ma davvero non dovrebbe. Dovresti concentrarti sulla verifica dei comportamenti osservabili esterni piuttosto che sull'implementazione.

L'ordine dei metodi può cambiare senza influire sul contratto con il client dell'API. In tal caso, il test fallirà, anche quando non dovrebbe.

In breve, l'implementazione dei test porta a test fragili. Test fragili portano all'abbandono dei test. Tu non vuoi andare lì.

Spero che questo aiuti.

+16

Questo non è sempre il caso. Esistono contratti di oggetti statici in cui l'ordine è importante e non è sempre possibile evitare tali contratti. – sanosdole

+0

Sono d'accordo con il commento di @sanosdole ma nel mio caso eri azzeccato. Dovrei testare il risultato ... non l'implementazione. Grazie! – MoMo

+0

Se il codice ha già un accoppiamento temporale, dovrebbe anche essere testato. – SerG

5

Ecco come farlo bene.

var mocks = new MockRepository(); 
var fooMock = mocks.DynamicMock<IFoo>(); 
using (mocks.Ordered()) 
{ 
    fooMock.Expect(x => x.Method1()); 
    fooMock.Expect(x => x.Method2()); 
} 
fooMock.Replay(); 

var bar = new Bar(fooMock); 
bar.DoWork(); 

fooMock.VerifyAllExpectations(); 

trovato la risposta from this blog.

+0

Ho dovuto modificare leggermente per farlo funzionare in RhinoMocks 3.5 - vedere la mia risposta qui sotto. – Clarkeye

+0

Non è la sintassi AAA. – SerG

1

Ecco come farlo con la costruzione di affermazioni in ogni chiamata di metodo.

// Arrange - Build the necessary assertions into the stubbed method invocations. 
var mock = MockRepository.GenerateMock<ISomeService>(); 
mock.Stub(m => m.Method1()).WhenCalled(inv => mock.AssertWasNotCalled(m => m.Method2())); 
mock.Stub(m => m.Method2()).WhenCalled(inv => mock.AssertWasNotCalled(m => m.Method3())); 

// Act 
myObject.Service = mock; 

// Assert - Ensure each expected method was called. 
mock.AssertWasCalled(m => m.Method1()); 
mock.AssertWasCalled(m => m.Method2()); 
mock.AssertWasCalled(m => m.Method3()); 

Poiché si tratta di mescola normale modello organizzare-act-assert eseguendo affermazioni a metà del gesto, mi piace di includere messaggi di errore molto specifiche per questi casi per identificare fallimenti dei test più facilmente.

mock.Stub(m => m.Method1()).WhenCalled(inv => 
    mock.AssertWasNotCalled(m => m.Method2(), opt => 
     opt.Message("Method2 cannot be called before Method1."))); 

Si può anche ottenere un risultato simile salvando il risultato di ciascuna chiamata in una variabile durante la fase atto, e quindi controllare gli stati variabili durante la fase di asserzione. Ciò preserva meglio la divisione del modello di assetto-atto-assert, ma è più un codice idraulico da scrivere e mantenere.

// Arrange - Build the necessary state variables into the stubbed method invocations. 
bool wasMethod1Called; 
bool wasMethod2Called; 
bool wasMethod2CalledBeforeMethod1; 
bool wasMethod3CalledBeforeMethod2; 

var mock = MockRepository.GenerateMock<ISomeService>(); 
mock.Stub(m => m.Method1()).WhenCalled(inv => 
{ 
    wasMethod1Called = true; 
}); 
mock.Stub(m => m.Method2()).WhenCalled(inv => 
{ 
    wasMethod2Called = true; 
    wasMethod2CalledBeforeMethod1 = !wasMethod1Called; 
}); 
mock.Stub(m => m.Method3()).WhenCalled(inv => 
{ 
    wasMethod3CalledBeforeMethod2 = !wasMethod2Called; 
}); 

// Act 
myObject.Service = mock; 

// Assert - Ensure each expected method was called, and that they were called in the right order. 
mock.AssertWasCalled(m => m.Method1()); 
mock.AssertWasCalled(m => m.Method2()); 
mock.AssertWasCalled(m => m.Method3()); 
Assert.That(wasMethod2CalledBeforeMethod1, Is.False, "Method2 cannot be called before Method1."); 
Assert.That(wasMethod3CalledBeforeMethod2, Is.False, "Method3 cannot be called before Method2."); 
0

La sintassi mocks.Ordered() specificata dal @craastad è il modo giusto per farlo, ma non ho potuto farlo funzionare in RhinoMocks 3.5 - invece ho dovuto modificarlo per lavorare senza l'istanza di MockRepository che @ soluzione craastad utilizzato per chiamare ordinato() su:

var fooMock = MockRepository.GenerateMock<IFoo>(); 
using (fooMock.GetMockRepository().Ordered()) 
{ 
    fooMock.Expect(x => x.Method1()); 
    fooMock.Expect(x => x.Method2()); 
} 

var bar = new Bar(fooMock); 
bar.DoWork(); 

fooMock.VerifyAllExpectations(); 

Se lo si fa in questo modo, sembra anche essere inutile chiamare fooMock.Replay() o.

+3

Qualcuno ha contrassegnato questa risposta in basso, il che è abbastanza giusto, ma se hai intenzione di farlo, il minimo che potresti è spiegare perché! – Clarkeye