2010-03-05 15 views
20

È corretto che stub e mock di Rhino Mocks siano utili solo per le interfacce, non per le classi concrete? Ho passato un bel po 'di tempo a cercare di far funzionare questo pezzo di codice. Non mi aspettavo che pubSubClient stoppato chiamasse sempre il metodo Send dalla classe. Questo metodo ha alcune dipendenze e genera un'eccezione.Rhino Mock stub e mock sono utili solo per le interfacce?

[Test] 
public void Test01() 
{ 
    PubSubMessage psm = new PubSubMessage(); 
    var pubSubClient = MockRepository.GenerateStub<PubSubClient>(); 
    pubSubClient.Stub(x => x.Send(psm)).IgnoreArguments().Return(null); 
    // actual PubSubClient Send method throws exception 
    // the rest of the test is skipped... 
} 

Tuttavia, quando ho estratto l'interfaccia ed eseguire la stessa prova con IPubSubClient, sembra funzionare come previsto.

Significa che devo estrarre l'interfaccia per ogni classe che voglio simulare/stubare con Rhino? O mi manca qualcosa, tecnicamente o concettualmente?

UPDATE: OK, Sembra che ho capito quale parte mi mancava: Rhino Mocks non può intercettare le chiamate a metodi non-virtuali. Quindi, suppongo di aver usato le interfacce o di rendere ogni metodo sulla classe concreta virtuale. Per favore correggimi se c'è un'altra opzione.

risposta

23

La risposta di Bryan all'uso di mock parziali non è corretta. Non è per quello che servono le paroline parziali.

La risposta di Jon Erickson è in gran parte corretta: Rhino Mock e Moq non possono intercettare le chiamate non virtuali, né possono intercettare metodi o proprietà statiche. Ciò significa che non puoi fingere quanto segue:

DateTime.Now; // static property, can't fake static property 
someClass.SomeNonVirtualMethod(); // can't fake non-virtual method 
sealedClass.Foo(); // can't fake anything on sealed classes 
Utilities.SomeStaticMethod(); // can't fake static methods 
someList.Any(); // can't fake extension methods like Linq's .Any() 

TypeMock può fingere questi, come ha detto Jon.

Va notato che esiste una struttura di simulazione aggiuntiva che può intercettare tutte le chiamate: Microsoft Moles framework. Funziona allo stesso modo di TypeMock, utilizza l'API del profiler .NET per intercettare le chiamate.

Moles è gratuito (per ora). È anche beta. Moles funziona solo con Microsoft Pex tools. E la sua API è chiaramente inferiore all'API raffinata ed elegante di TypeMock.

+4

Se si specifica che le parolacce parziali non sono per qualcosa, è più utile dire cosa sono nella risposta. I mazzi parziali hanno lo scopo di prendere in giro solo parte di una classe, questo li rende a portata di mano (e necessari) per prendere in giro una classe astratta in cui un normale finto non può gestirlo. Ciò consente di testare metodi astratti. Un mock parziale (almeno in Rhino) deriderà qualsiasi classe e non è limitato alle classi Abstract, siate comunque consapevoli se c'è un codice di implementazione che verrà richiamato al momento del ritorno. –

+0

(avviso necro): Ho appena scoperto che la tua classe non ha nemmeno bisogno di essere astratta per rendere i metodi virtuali! Una cosa così piccola, ma non l'ho mai considerato prima :-) – Heliac

1

Le mock parziali consentono di prendere in giro la funzionalità di una classe di calcestruzzo. Vedi: http://www.ayende.com/wiki/Rhino+Mocks+Partial+Mocks.ashx

+0

Ho paura che le parate parziali non lo facciano. Sono d'aiuto nel prendere in giro alcuni metodi non implementati in classi astratte, ma se c'è un'implementazione, viene ancora chiamata. In altre parole, nel mio esempio, la sostituzione di MockRepository.GenerateStub () con MockRepository.GeneratePartialMock () non modifica nulla. –

+1

rendere virtuale il tuo metodo. –

3

Devi rendere i metodi virtuali. Rhino mocks (e la maggior parte degli altri framework di isolamento) utilizza classi proxy per creare gli stub/mock.

Se si utilizza TypeMock Isolator si può prendere in giro nulla, perché questo quadro l'isolamento utilizza .NET Profiler API al fine di creare le sue stub/deride

+0

+1. Come l'OP menzionato nel suo aggiornamento, i metodi devono essere virtuali. Questo vale anche per Moq e (credo) per ogni framework di isolamento .NET ad eccezione di TypeMock Isolator. La soluzione economica e facile è rendere i metodi virtuali (o estrarre un'interfaccia). – TrueWill

0

Io non credo che ci sia un altro modo di fare questo diverso da fare qualsiasi metodo tu voglia imitare virtuale - Credo che il modo in cui le mazze di classi concrete vengono create è dinamicamente sottoclassando la classe concreta che viene derisa e poi sovrascrivendo i metodi dati con il comportamento specificato nel test, quindi questo richiede un metodo virtuale per funzionare correttamente.

2

Questo è sostanzialmente corretto ed è generalmente una buona pratica. Tuttavia, è solo veramente utile per un tipo specifico di codifica.

Non pensare agli oggetti come a cose che un "potere superiore" può manipolare. Invece, pensa a loro come "persone" autonome che possono inviare messaggi a vicenda. Un'interfaccia rappresenta i messaggi inviati da un singolo oggetto.

Quindi si utilizzano i mock per verificare che siano stati inviati i messaggi corretti, non per fornire false implementazioni delle dipendenze.

Idealmente, non si crea un'interfaccia che corrisponda esattamente a una classe esistente - invece, la classe che consuma l'interfaccia dichiara le proprie esigenze sotto forma di un'interfaccia.