Votre question portait sur la façon dont le cadre MS Fakes est différent de NMock et il semble que les autres réponses ont résolu certains de ces problèmes, mais voici quelques informations supplémentaires sur la manière dont ils sont identiques et sur la manière dont ils sont différents. NMock est également similaire à RhinoMocks et Moq, je les regroupe donc avec NMock.
Il y a 3 différences majeures que je vois d'emblée entre NMock / RhinoMocks / Moq et le MS Fakes Framework:
Le framework MS fakes utilise du code généré, un peu comme les accesseurs dans les versions précédentes de Visual Studio au lieu de types génériques. Lorsque vous souhaitez utiliser le faux framework pour une dépendance, vous ajoutez l'assembly qui contient la dépendance aux références du projet de test, puis cliquez dessus avec le bouton droit de la souris pour générer les doubles de test (stubs ou shims). Ensuite, lorsque vous testez, vous utilisez en fait ces classes générées à la place. NMock utilise des génériques pour accomplir la même chose (ie IStudentRepository studentRepository = mocks.NewMock<IStudentRepository>()
). À mon avis, l'approche du cadre MS Fakes inhibe la navigation dans le code et la refactorisation à partir des tests puisque vous travaillez en fait contre une classe générée, pas votre véritable interface.
Le cadre de faux MS fournit des talons et des taupes (cales), tandis que NMock, RhinoMocks et Moq fournissent tous des talons et des mocks . Je ne comprends vraiment pas la décision de MS de ne pas inclure de simulacres et je ne suis personnellement pas fan des taupes pour les raisons décrites ci-dessous.
Avec le framework MS fakes, vous fournissez une implémentation alternative des méthodes que vous souhaitez stub. Dans ces autres implémentations, vous pouvez spécifier les valeurs de retour et suivre les informations sur la façon ou si la méthode a été appelée. Avec NMock, RhinoMocks et Moq, vous générez un objet fictif, puis utilisez cet objet pour spécifier des valeurs de retour stubbed ou pour suivre les interactions (si et comment les méthodes ont été appelées). Je trouve l'approche des faux MS plus complexe et moins expressive.
Pour clarifier la différence dans ce que fournissent les frameworks: NMock, RhinoMocks et Moq fournissent tous deux types de tests doubles (stubs et mocks). Le faux framework fournit des talons et des taupes (ils les appellent des cales) et n'inclut malheureusement pas les simulacres. Afin de comprendre les différences et les similitudes entre NMock et MS Fakes, il est utile de comprendre quels sont ces différents types de doubles de test:
Stubs: Les stubs sont utilisés lorsque vous devez fournir des valeurs pour des méthodes ou des propriétés qui seront demandées à vos doubles de test par la méthode testée. Par exemple, lorsque ma méthode sous test appelle la méthode DoesStudentExist () du test double IStudentRepository, je veux qu'elle renvoie true.
L'idée des stubs dans les faux NMock et MS est la même, mais avec NMock, vous feriez quelque chose comme ceci:
Stub.On(mockStudentRepository).Method("DoesStudentExist").Will(Return.Value(true));
Et avec MSFakes, vous feriez quelque chose comme ceci:
IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() // Generated by Fakes.
{
DoesStudentExistInt32 = (studentId) => { return new Student(); }
};
Remarquez dans l'exemple MS Fakes que vous créez une implémentation entièrement nouvelle pour la méthode DoesStudentExist (notez qu'elle s'appelle DoesStudentExistInt32 car le faux framework ajoute les types de données de paramètre aux noms de méthode lorsqu'il génère les objets stub, je pense que cela obscurcit la clarté de les tests). Pour être honnête, l'implémentation NMock me dérange également car elle utilise une chaîne pour identifier le nom de la méthode. (Pardonnez-moi si j'ai mal compris comment NMock est destiné à être utilisé.) Cette approche inhibe vraiment le refactoring et je recommande vivement RhinoMocks ou Moq sur NMock pour cette raison.
Mocks: les Mocks sont utilisés pour vérifier l'interaction entre votre méthode testée et ses dépendances. Avec NMock, vous faites cela en définissant des attentes similaires à ceci:
Expect.Once.On(mockStudentRepository).Method("Find").With(123);
C'est une autre raison pour laquelle je préférerais RhinoMocks et Moq à NMock, NMock utilise l'ancien style d'attente alors que RhinoMocks et Moq prennent tous deux en charge l'approche Arrange / Act / Assert où vous spécifiez les interactions attendues sous forme d'assertions à la fin du test comme ceci :
stubStudentRepository.AssertWasCalled( x => x.Find(123));
Encore une fois, notez que RhinoMocks utilise un lambda au lieu d'une chaîne pour identifier la méthode. Le framework ms fakes ne fournit pas du tout de simulations. Cela signifie que dans vos implémentations stubbed (voir la description des stubs ci-dessus), vous devez définir des variables que vous vérifierez plus tard qu'elles étaient correctement définies. Cela ressemblerait à quelque chose comme ceci:
bool wasFindCalled = false;
IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository()
{
DoesStudentExistInt32 = (studentId) =>
{
wasFindCalled = true;
return new Student();
}
};
classUnderTest.MethodUnderTest();
Assert.IsTrue(wasFindCalled);
Je trouve que cette approche est un peu compliquée car vous devez suivre l'appel dans le talon, puis l'affirmer plus tard dans le test. Je trouve que les exemples NMock, et en particulier les RhinoMocks, sont plus expressifs.
Moles (Shims): Pour être franc, je n'aime pas les grains de beauté, en raison de leur potentiel d'abus. Une des choses que j'aime tant dans les tests unitaires (et TDD en particulier) est que tester votre code vous aide à comprendre où vous avez écrit un code médiocre. En effet, il est difficile de tester un code mal écrit. Ce n'est pas le cas lors de l'utilisation de moles, car les moles sont en fait conçues pour vous permettre de tester des dépendances qui ne sont pas injectées ou de tester des méthodes privées. Ils fonctionnent de la même manière que les stubs, sauf que vous utilisez un ShimsContext comme celui-ci:
using (ShimsContext.Create())
{
System.Fakes.ShimDateTime.NowGet = () => { return new DateTime(fixedYear, 1, 1); };
}
Mon souci avec les shims est que les gens commenceront à les voir comme "un moyen plus simple de tester les unités" car cela ne vous oblige pas à écrire du code comme vous le devriez. Pour un article plus complet sur ce concept, consultez mon article:
Pour plus d'informations sur certaines préoccupations liées aux faux frameworks, consultez ces articles:
Si vous êtes intéressé à apprendre RhinoMocks, voici une vidéo de formation Pluralsight (divulgation complète - j'ai écrit ce cours et je reçois des redevances payées pour les vues, mais je pense que cela s'applique à cette discussion, je l'inclus ici):