La tua domanda riguardava il modo in cui il framework MS Fakes è diverso da NMock e sembra che le altre risposte abbiano risolto alcuni di questi problemi, ma qui ci sono alcune informazioni in più su come sono gli stessi e come sono diversi. NMock è anche simile a RhinoMocks e Moq, quindi li sto raggruppando con NMock.
Ci sono 3 differenze principali che vedo subito tra NMock / RhinoMocks / Moq e MS Fakes Framework:
Il framework MS Fakes utilizza codice generato, molto simile a Accessors nelle versioni precedenti di Visual Studio invece di tipi generici. Quando si desidera utilizzare il framework falsi per una dipendenza, aggiungere l'assembly che contiene la dipendenza ai riferimenti del progetto di test e quindi fare clic con il pulsante destro del mouse su di esso per generare i doppi di test (stub o shim). Quindi, quando esegui il test, stai effettivamente utilizzando invece queste classi generate. NMock utilizza generici per realizzare la stessa cosa (cioè IStudentRepository studentRepository = mocks.NewMock<IStudentRepository>()
). A mio parere, l'approccio del framework MS Fakes inibisce la navigazione del codice e il refactoring dall'interno dei test poiché stai effettivamente lavorando su una classe generata, non sulla tua vera interfaccia.
Il framework MS Fakes fornisce stub e talpe (shim), mentre NMock, RhinoMocks e Moq forniscono tutti stub e mock . Non capisco davvero la decisione di MS di non includere i mock e io personalmente non sono un fan dei nei per i motivi descritti di seguito.
Con il framework MS Fakes, fornisci un'implementazione alternativa dei metodi che desideri stub. All'interno di queste implementazioni alternative, è possibile specificare i valori restituiti e tenere traccia delle informazioni su come o se il metodo è stato chiamato. Con NMock, RhinoMocks e Moq, si genera un oggetto fittizio e quindi si utilizza quell'oggetto per specificare i valori di ritorno stub o per tenere traccia delle interazioni (se e come sono stati chiamati i metodi). Trovo l'approccio dei falsi alla SM più complesso e meno espressivo.
Per chiarire la differenza in ciò che forniscono i framework: NMock, RhinoMocks e Moq forniscono tutti due tipi di doppioni di test (stub e mock). La struttura dei falsi fornisce mozziconi e talpe (li chiamano spessori) e sfortunatamente non include simulazioni. Per comprendere le differenze e le somiglianze tra NMock e MS Fakes, è utile capire quali sono questi diversi tipi di doppi di test:
Stub: gli stub vengono utilizzati quando è necessario fornire valori per metodi o proprietà che verranno richiesti ai doppi di test dal metodo sottoposto a test. Ad esempio, quando il mio metodo sottoposto a test chiama il metodo DoesStudentExist () del doppio di test IStudentRepository, voglio che restituisca true.
L'idea degli stub nei falsi NMock e MS è la stessa, ma con NMock faresti qualcosa del genere:
Stub.On(mockStudentRepository).Method("DoesStudentExist").Will(Return.Value(true));
E con MSFakes faresti qualcosa di simile:
IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() // Generated by Fakes.
{
DoesStudentExistInt32 = (studentId) => { return new Student(); }
};
Si noti nell'esempio di MS Fakes che si crea un'implementazione completamente nuova per il metodo DoesStudentExist (si noti che si chiama DoesStudentExistInt32 perché il framework fakes aggiunge i tipi di dati dei parametri ai nomi dei metodi quando genera gli oggetti stub, penso che questo offuschi la chiarezza di i test). Ad essere onesti l'implementazione di NMock mi infastidisce anche perché usa una stringa per identificare il nome del metodo. (Perdonatemi se ho frainteso come si intende usare NMock.) Questo approccio inibisce davvero il refactoring e per questo motivo consiglio vivamente RhinoMocks o Moq su NMock.
Mock: i mock vengono utilizzati per verificare l'interazione tra il metodo sottoposto a test e le sue dipendenze. Con NMock, lo fai impostando aspettative simili a questa:
Expect.Once.On(mockStudentRepository).Method("Find").With(123);
Questo è un altro motivo per cui preferirei RhinoMocks e Moq su NMock, NMock utilizza il vecchio stile di aspettativa mentre RhinoMocks e Moq supportano entrambi l'approccio Arrange / Act / Assert in cui specifichi le interazioni previste come affermazioni alla fine del test come questo :
stubStudentRepository.AssertWasCalled( x => x.Find(123));
Ancora una volta, nota che RhinoMocks usa un lambda invece di una stringa per identificare il metodo. Il framework ms fakes non fornisce affatto mock. Ciò significa che nelle implementazioni bloccate (vedere la descrizione degli stub sopra) devi impostare le variabili che successivamente verifichi siano state impostate correttamente. Sarebbe simile a questo:
bool wasFindCalled = false;
IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository()
{
DoesStudentExistInt32 = (studentId) =>
{
wasFindCalled = true;
return new Student();
}
};
classUnderTest.MethodUnderTest();
Assert.IsTrue(wasFindCalled);
Trovo che questo approccio sia un po 'complicato poiché devi tenere traccia della chiamata nello stub e quindi affermarla più avanti nel test. Trovo che gli esempi NMock, e in particolare RhinoMocks, siano più espressivi.
Talpe (Shims): Ad essere sincero, non mi piacciono le talpe, a causa del loro potenziale uso improprio. Una delle cose che mi piacciono così tanto del test unitario (e del TDD in particolare) è che il test del codice ti aiuta a capire dove hai scritto codice scadente. Questo perché è difficile testare un codice scritto male. Questo non è vero quando si usano le talpe perché le talpe sono effettivamente progettate per consentire di testare dipendenze che non vengono iniettate o per testare metodi privati. Funzionano in modo simile agli stub, tranne per il fatto che usi un ShimsContext come questo:
using (ShimsContext.Create())
{
System.Fakes.ShimDateTime.NowGet = () => { return new DateTime(fixedYear, 1, 1); };
}
La mia preoccupazione con gli spessori è che le persone inizieranno a vederli come "un modo più semplice per test unitari" perché non ti obbliga a scrivere codice nel modo in cui dovresti. Per un resoconto più completo su questo concetto, guarda questo mio post:
Per ulteriori informazioni su alcune preoccupazioni relative ai framework falsi, dai un'occhiata a questi post:
Se sei interessato a imparare RhinoMocks, ecco un video di formazione Pluralsight (divulgazione completa - ho scritto questo corso e vengo pagato le royalty per le visualizzazioni, ma penso che si applichi a questa discussione, quindi lo includo qui):