Framework simulé vs frameworks MS Fakes


99

Un peu confus sur les différences entre les frameworks Mock comme NMock et le VS 2011 Fakes Framework. En passant par MSDN, ce que je comprends, c'est que Fakes vous permet de vous moquer de vos dépendances tout comme RhinoMock ou NMock, mais l'approche est différente, Fakes génère du code pour atteindre cette fonctionnalité mais pas le framework Mocks. Alors ma compréhension est-elle correcte? Est-ce que Fakes est juste un autre framework Mock

Réponses:


189

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):


14
@Jim Je ne suis pas d'accord pour dire que permettre à quelqu'un de "tester contre des dépendances qui ne sont pas injectées" est une mauvaise chose. Au contraire, en pratique, cette capacité permet d'éviter d'encombrer une base de code avec beaucoup d'interfaces inutiles et la configuration / complexité associée de "câblage d'objet". J'ai déjà vu quelques projets (Java et .NET) qui avaient des centaines d'interfaces Java / C # avec une seule classe d'implémentation, et beaucoup de configuration XML inutile (pour les beans Spring DI, ou dans Web.config pour MS Unity cadre). Il vaut mieux ne pas injecter de telles dépendances .
Rogério

19
@Rogerio, j'ai travaillé sur plusieurs projets avec des milliers de classes qui suivent ce modèle et lorsque l'injection de dépendances est bien faite (si vous utilisez la configuration XML, vous ne le faites pas correctement, à mon humble avis), c'est simple et relativement indolore. D'un autre côté, j'ai travaillé sur des systèmes qui ne le font pas et le couplage entre les classes m'a toujours causé une douleur importante. Le test n'est pas la raison d'utiliser l'injection de dépendances (bien que ce ne soit pas une mauvaise raison). La vraie raison est le couplage desserré. Avoir des interfaces implémentées par une seule classe ne m'a jamais causé de douleur.
Jim Cooper

17
@Jim, je vois la possibilité de tester un mauvais design comme un grand plus. La première chose à faire avant de refactoriser le code hérité vers une meilleure conception est d'écrire des tests.
Thomas Materna

4
Ma règle est que j'utilise Fakes uniquement lorsque je dois Shim une méthode partagée / statique ou une classe à laquelle je n'ai pas accès pour implémenter une interface. Pour tout le reste, j'utilise Moq. Les faux sont plus lents (car les faux assemblages doivent être générés) et il faut plus d'efforts de codage pour correspondre aux fonctionnalités que vous obtenez avec Moq.
Nick

5
@ CarloV.Dango Tout d'abord, je sais parfaitement que l'injection de dépendances ne nécessite pas d'interfaces séparées; mon commentaire précédent faisait juste allusion à la tendance à créer de telles interfaces lors de l'utilisation de DI. Deuxièmement, "IOC" (Inversion of Control) n'a rien à voir avec DI! (Le premier concerne l'inversion du flux de contrôle entre les méthodes, tandis que le second concerne la résolution des dépendances pour un composant / objet.) En confondant IOC et DI, c'est vous qui montrez l'ignorance, pas moi; et, franchement, ce site ne mérite pas que les gens insultent les autres, alors s'il vous plaît, gardons-le civil.
Rogério

23

Vous avez raison, mais il y a plus dans l'histoire. Les choses les plus importantes à retenir de cette réponse sont:

  1. Votre architecture doit utiliser correctement les stubs et l'injection de dépendances, plutôt que de compter sur la béquille de faux et de simulations

  2. Les faux et les simulacres sont utiles pour tester le code que vous ne devriez pas ou ne pouvez pas changer, comme:

    • Code hérité qui n'utilise pas (ou n'utilise pas efficacement) les stubs
    • API tierces
    • Ressources pour lesquelles vous n'avez pas de code source

Shims (connu sous le nom de "Moles", lors du développement) est en effet un cadre moqueur qui fonctionne par des appels détournés. Au lieu de construire minutieusement une maquette (oui, même l'utilisation de Moq est relativement pénible!), Les shims utilisent simplement l'objet de code de production déjà en place. Les shims réacheminent simplement l'appel de la cible de production vers le délégué de test.

Les stubs sont générés à partir des interfaces du projet cible. L'objet Stub n'est que cela - une implémentation de l'interface. L'avantage d'utiliser le type Stub est que vous pouvez générer rapidement un stub sans encombrer votre projet de test avec de nombreux stubs à usage unique, sans parler de perdre du temps à les créer. Bien sûr, vous devez toujours créer des stubs concrets, à utiliser dans de nombreux tests.

La mise en œuvre efficace de Fakes (types Shims, Mocks et Stub) prend un peu de temps pour s'y habituer, mais cela en vaut la peine. J'ai personnellement économisé des semaines de temps de développement, grâce à l'utilisation des types Shims / Mole, Mocks et Stub. J'espère que vous vous amuserez autant que moi avec la technologie!


11
Évalué en raison du manque de détails et de certains problèmes de terminologie avec vos commentaires sur les faux. Fakes est un terme général pour tous les types de tests doubles et aussi le nom MS utilisé pour leur fake library. Dans leur bibliothèque, seuls les shims sont en fait des taupes, les talons ne le sont pas. En ce qui concerne le besoin d'exemples, j'aimerais voir un exemple dans votre réponse qui montre comment créer un shim (ou un stub) avec Fakes est plus simple que d'utiliser Moq. Si vous modifiez votre réponse pour résoudre ces problèmes, je modifierai mon vote défavorable.
Jim Cooper

1
Mais ajoute une bonne justification à l'utilisation de cales (moles), c'est-à-dire du code tiers, des API système / SDK. Il ne s'agit pas seulement de travailler avec vos propres solutions internes. Donc, je vais vous lever une voix pour égaliser cela :-)
Tony Wall

2
@Mike et Jim .. J'ai fait des efforts pour corriger la terminologie utilisée dans cette réponse. S'il vous plaît laissez-moi savoir si nous pouvons l'améliorer. Merci.
Snesh

15

Si je comprends bien, l'équipe de Visual Studio a voulu éviter de concurrencer les diverses bibliothèques simulées disponibles pour .NET. La SP est souvent confrontée à des décisions difficiles comme celle-ci. Ils sont bloqués s'ils ne fournissent pas certaines fonctionnalités ("pourquoi MS ne nous fournit-il pas une fausse bibliothèque; les simulations sont une exigence si courante?") Et damnés s'ils le font ("pourquoi Microsoft agit-il si agressivement et partisans naturels du marché? ") Très souvent, mais pas toujours, ils décident de ne pas simplement fournir leur propre alternative aux technologies disponibles et bien accueillies. Cela semble être le cas ici.

La fonction de cale de Fakes est vraiment, vraiment utile. Bien sûr, il y a des dangers. Il faut une certaine discipline pour s'assurer que vous ne l'utilisez que lorsque c'est nécessaire. Cependant, cela comble un grand vide. Ma principale plainte est qu'il n'est livré qu'avec l'édition Ultimate de VS 2012 et ne sera donc disponible que pour une sous-section de la communauté de développement .NET. Quel dommage.


2
Le faux framework est également disponible avec l'édition Premium.
AlwaysAProgrammer

13

Fakes comprend deux types différents de "faux" objets. Le premier, appelé "stub", est essentiellement un mannequin auto-généré dont le comportement par défaut peut (et serait généralement) remplacé pour en faire un simulacre plus intéressant. Il manque cependant certaines des fonctionnalités offertes par la plupart des frameworks de simulation actuellement disponibles. Par exemple, si vous voulez vérifier qu'une méthode sur une instance de stub a été appelée, vous devez ajouter vous-même la logique pour cela. Fondamentalement, si vous créez vos propres simulations manuellement maintenant, les stubs sembleraient probablement une amélioration. Cependant, si vous utilisez déjà un cadre de simulation plus complet, vous pourriez avoir l'impression qu'il manque des pièces importantes dans les faux stubs.

L'autre catégorie d'objet proposée par Fakes, appelée «shim», expose un mécanisme de remplacement du comportement de dépendances qui n'ont pas été (ou ne peuvent pas être) découplées de manière adéquate pour un remplacement standard via des simulacres. AFAIK, TypeMock est le seul des principaux frameworks moqueurs à offrir actuellement ce type de fonctionnalités.

BTW, si vous avez déjà essayé Moles, Fakes est essentiellement la même chose, finissant par sortir de Microsoft Research et devenir un produit réel.


1
Mise à jour: Moles a maintenant été intégré dans MS Fakes. "Le framework Fakes dans Visual Studio 2012 est la prochaine génération de Moles & Stubs. Fakes est différent de Moles, cependant, le passage de Moles à Fakes nécessitera quelques modifications de votre code. Le framework Moles ne sera pas pris en charge dans Visual Studio 2012 . " Source: research.microsoft.com/en-us/projects/moles
Sire

1

En ce qui concerne les objets Fake (Shim + Stub), cela a été bien défini ci-dessus, bien que je suppose que le dernier paragraphe du dernier commentaire résume assez bien la situation dans son ensemble.

Bien que beaucoup de gens soutiennent que les objets Fake (Shim + Stub) sont de bons atouts à avoir dans certains cas de test unitaire, l'inconvénient est que peu importe si vous utilisez Visual Studio 2012 ou Visual Studio 2013, ces options sont UNIQUEMENT disponibles avec les versions Premium ou Ultimate. IOW, cela signifie que vous NE SEREZ AUCUN de ces faux (Shim + Stub) sur aucune version Pro.

Vous pouvez probablement voir l'option de menu Fakes (Shim + Stub) sur les versions Pro, mais attention, il y a de fortes chances que vous vous retrouviez avec absolument rien ... Cela ne générera aucune erreur de compilation vous indiquant que quelque chose d'important manque, les options ne sont tout simplement pas là, alors ne perdez pas votre temps ...

C'est un facteur important à prendre en compte dans une équipe de développement, surtout si l'un est le seul à utiliser la version Ultimate alors que tout le monde utilise la version Pro ... Moq, d'autre part, peut facilement être installé via Nuget, quelle que soit la version de Visual Studio que vous utilisez. Je n'ai eu aucun problème à utiliser Moq, la clé de tout outil est de savoir à quoi ils servent et comment les utiliser correctement;)


1
Veuillez formater votre question en paragraphes plus petits pour qu'elle soit plus facile à lire.

@SirXamelot, sans refactoriser le code, vous ne pouvez pas modifier la sortie des appels statiques fournis par .net, par exemple DateTime.Now ou Guid.NewGuid
zaitsman
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.