2012-05-23 10 views
18

Sto cercando di scoprire come posso prendere in giro un metodo che restituisce un valore diverso la seconda volta che viene chiamato al primo tempo. Ad esempio, qualcosa di simile:RhinoMocks - mocking un metodo il cui valore di ritorno cambia (anche quando ha passato lo stesso parametro) con più chiamate

public interface IApplicationLifetime 
{ 
    int SecondsSinceStarted {get;} 
} 

[Test] 
public void Expected_mock_behaviour() 
{ 
    IApplicationLifetime mock = MockRepository.GenerateMock<IApplicationLifetime>(); 

    mock.Expect(m=>m.SecondsSinceStarted).Return(1).Repeat.Once(); 
    mock.Expect(m=>m.SecondsSinceStarted).Return(2).Repeat.Once(); 

    Assert.AreEqual(1, mock.SecondsSinceStarted); 
    Assert.AreEqual(2, mock.SecondsSinceStarted); 
} 

C'è qualcosa che lo rende possibile? Oltre all'implementazione di un sub per il getter che implementa una macchina a stati?

Acclamazioni ragazzi,

Alex

+0

Dai un'occhiata ai mock ordinati e non ordinati: http://ayende.com/wiki/Rhino%20Mocks%20Ordered%20and%20Unordered.ashx – Maciej

+2

Cosa c'è di sbagliato nel codice che hai fornito? 'Repeat.Once()' dovrebbe funzionare –

+0

@lazyberezovsky La prima chiamata a m.SecondsSinceStarted restituisce 2, non 1 come previsto – AlexC

risposta

28

è possibile intercettare i valori di ritorno con .WhenCalled metodo. Si noti che è ancora necessario fornire valore attraverso .Return metodo, tuttavia Rhino semplicemente ignorare se ReturnValue è alterata dalla chiamata di metodo:

int invocationsCounter = 1; 
const int IgnoredReturnValue = 10; 
mock.Expect(m => m.SecondsSinceLifetime) 
    .WhenCalled(mi => mi.ReturnValue = invocationsCounter++) 
    .Return(IgnoredReturnValue); 

Assert.That(mock.SecondsSinceLifetime, Is.EqualTo(1)); 
Assert.That(mock.SecondsSinceLifetime, Is.EqualTo(2)); 

Edit:

Scavando attorno a un po 'di più, sembra che .Repeat.Once()fa effettivamente funziona in questo caso e può essere utilizzato per ottenere lo stesso risultato:

mock.Expect(m => m.SecondsSinceStarted).Return(1).Repeat.Once(); 
mock.Expect(m => m.SecondsSinceStarted).Return(2).Repeat.Once(); 
mock.Expect(m => m.SecondsSinceStarted).Return(3).Repeat.Once(); 

Restituisce 1, 2, 3 su chiamate consecutive.

+0

Come ho capito, per qualcosa di diverso dai numeri sequenziali dovrebbe creare array e restituire i valori per indice? –

+0

Sono d'accordo che questo metodo funziona, ma questo è essenzialmente lo stesso di dover implementare una macchina a stati, che ho menzionato sto cercando di evitare (ad es.se volessi restituire 11 in seconda chiamata, allora avrei bisogno di fare qualcosa come "if (invocationsCounter == 1) restituire 1, altrimenti if (invocationsCounter == 2) return 11;" che assomiglia molto a una macchina a stati. – AlexC

+0

Oggetto: la tua modifica. Non sono sicuro se questa è una funzionalità che è cambiata nella versione di RhinoMocks che sto usando e quella che stai usando, ma ho eseguito il test che è nella mia domanda originale e posso dirti che non funziona (ovvero la prima chiamata a SecondsSinceStarted restituisce 2). Hai un link dove hai trovato che funziona? – AlexC

0

Il tempo è il fattore determinante in ciò che il metodo restituisce? In tal caso, proverei ad astrarre il passaggio temporale in modo da avere il controllo diretto su di esso nei test.

Qualcosa come un'interfaccia chiamata ITimeProvider con un membro chiamato GetElapsedTime() e quindi creare un'implementazione predefinita da utilizzare in tutta l'applicazione.

Quindi, quando si esegue il test, passare un ITimeProvider deriso in modo da controllare ciò che viene percepito dall'applicazione per il passare del tempo.

+0

In realtà, la cosa del tempo era solo un esempio pratico senza descrivere completamente cosa sto provando a testare. Anche così, se volessi prendere in giro un ITimeProvider, che aveva un metodo GetElapsedTime(), il problema sarebbe ancora presente se volessi scrivere un test unitario che chiamasse GetElapsedTime() due volte, e volevo che il mio simulato ITimeProvider restituisse un altro tempo per ogni chiamata. – AlexC

+0

È possibile che ITimeProvider sia una dipendenza di proprietà? Quindi essere in grado di iniettare nuovi mock prima di ogni chiamata? Anche se non ha tempo, la mia risposta è probabilmente senza valore ... – theMothaShip

+0

La mia domanda era più se RhinoMocks supporta questo tipo di interazione con mock/stub generati, e meno su come potrei aggirarlo, non dovrebbe essere supportato. Grazie comunque. – AlexC

5

Basta usare

mock.Expect(m=>m.SecondsSinceStarted).Return(1).Repeat.Once(); 
mock.Expect(m=>m.SecondsSinceStarted).Return(2).Repeat.Once(); 

Questo restituirà 1 durante la prima chiamata, e 2 durante la seconda chiamata. Almeno su RhinoMocks 3.6.0.0

+0

Questo è sicuramente in conflitto con quello che vedo quando eseguo il test sopra – AlexC

+0

Come accennato nella risposta accettata, questo è corretto, il mio test stava fallendo solo mentre stavo passando e valutando qualcosa inavvertitamente. Upvoted. – AlexC

Problemi correlati