Je sais comment j'utilise ces termes, mais je me demande s'il existe des définitions acceptées pour truquer , se moquer et écraser pour les tests unitaires? Comment les définissez-vous pour vos tests? Décrivez les situations dans lesquelles vous pourriez les utiliser.
Voici comment je les utilise:
Fake : une classe qui implémente une interface mais contient des données fixes et aucune logique. Renvoie simplement les «bonnes» ou «mauvaises» données selon la mise en œuvre.
Mock : une classe qui implémente une interface et permet de définir dynamiquement les valeurs à renvoyer / exceptions à lancer à partir de méthodes particulières et offre la possibilité de vérifier si des méthodes particulières ont été appelées / non appelées.
Stub : comme une classe fictive, sauf qu'elle ne permet pas de vérifier que les méthodes ont été appelées / non appelées.
Les maquettes et les talons peuvent être générés à la main ou générés par un cadre de simulation. Les fausses classes sont générées à la main. J'utilise principalement des simulations pour vérifier les interactions entre ma classe et les classes dépendantes. J'utilise des talons une fois que j'ai vérifié les interactions et que je teste des chemins alternatifs dans mon code. J'utilise de fausses classes principalement pour faire abstraction des dépendances de données ou lorsque les mocks / stubs sont trop fastidieux à configurer à chaque fois.
Réponses:
Vous pouvez obtenir des informations:
De Martin Fowler à propos de Mock and Stub
Les faux objets ont en fait des implémentations fonctionnelles, mais prennent généralement un raccourci qui les rend non adaptés à la production
Les talons fournissent des réponses prédéfinies aux appels effectués pendant le test, ne répondant généralement pas du tout à ce qui est en dehors de ce qui est programmé pour le test. Les talons peuvent également enregistrer des informations sur les appels, comme un talon de passerelle de messagerie qui se souvient des messages qu'il a «envoyés», ou peut-être seulement du nombre de messages qu'il a «envoyés».
Les maquette sont ce dont nous parlons ici: des objets préprogrammés avec des attentes qui forment une spécification des appels qu'ils sont censés recevoir.
De xunitpattern :
Faux : Nous acquérons ou construisons une implémentation très légère de la même fonctionnalité que celle fournie par un composant dont dépend le SUT et demandons au SUT de l'utiliser au lieu du réel.
Stub : cette implémentation est configurée pour répondre aux appels du SUT avec les valeurs (ou exceptions) qui exerceront le code non testé (voir Bogues de production à la page X) dans le SUT. Une indication clé pour l'utilisation d'un talon de test est d'avoir un code non testé dû à l'incapacité de contrôler les entrées indirectes du SUT
Mock Object qui implémente la même interface qu'un objet dont dépend le SUT (System Under Test). Nous pouvons utiliser un objet simulé comme point d'observation lorsque nous devons effectuer une vérification du comportement pour éviter d'avoir une exigence non testée (voir Bogues de production à la page X) causée par une incapacité à observer les effets secondaires de l'invocation de méthodes sur le SUT.
Personnellement
J'essaie de simplifier en utilisant: Mock et Stub. J'utilise Mock lorsqu'il s'agit d'un objet qui renvoie une valeur définie sur la classe testée. J'utilise Stub pour imiter une classe Interface ou Abstract à tester. En fait, peu importe comment vous l'appelez, ce sont toutes des classes qui ne sont pas utilisées en production et sont utilisées comme classes utilitaires pour les tests.
la source
Stub - un objet qui fournit des réponses prédéfinies aux appels de méthode.
Mock - un objet sur lequel vous définissez des attentes.
Faux - un objet aux capacités limitées (à des fins de test), par exemple un faux service Web.
Test Double est le terme général pour les talons, les faux et les faux. Mais de manière informelle, vous entendrez souvent des gens les appeler simplement des simulacres.
la source
EXPECT_CALL()
s sur une méthode simulée qui force certaines sorties en fonction de certaines entrées, en utilisant le type.WillOnce(Invoke(my_func_or_lambda_func))
(ou avec.WillRepeatedly()
) syntaxe attachée à unEXPECT_CALL()
. Quelques exemples d'utilisationInvoke()
peuvent être vus dans un contexte différent au bas de ma longue réponse ici: stackoverflow.com/a/60905880/4561887 .Invoke()
est ici: github.com/google/googletest/blob/master/googlemock/docs/… . Quoi qu'il en soit, la conclusion est la suivante: Google mock (gmock) permet de créer facilement des mocks et des stubs , bien que la plupart des mocks ne soient pas des stubs.Je suis surpris que cette question existe depuis si longtemps et personne n'a encore fourni de réponse basée sur "The Art of Unit Testing" de Roy Osherove .
Dans "3.1 Présentation des stubs", un stub est défini comme:
Et définit la différence entre les talons et les faux comme:
Fake n'est que le nom utilisé pour les talons et les simulacres. Par exemple lorsque vous ne vous souciez pas de la distinction entre les talons et les faux
La façon dont Osherove fait la distinction entre les talons et les faux, signifie que toute classe utilisée comme faux pour les tests peut être à la fois un talon ou un faux. Ce que c'est pour un test spécifique dépend entièrement de la façon dont vous écrivez les chèques dans votre test.
Exemple de test où la classe FakeX est utilisée comme stub:
L'
fake
instance est utilisée en tant que stub car leAssert
n'utilise pasfake
du tout.Exemple de test où la classe de test X est utilisée comme maquette:
Dans ce cas, la
Assert
vérifie une valeurfake
, ce qui en fait un faux.Maintenant, bien sûr, ces exemples sont très artificiels, mais je vois un grand mérite dans cette distinction. Il vous fait savoir comment vous testez vos trucs et où se trouvent les dépendances de votre test.
Je suis d'accord avec Osherove que
Affirmer contre le faux est quelque chose que vous voulez vraiment éviter car cela rend vos tests très dépendants de l'implémentation d'une classe qui n'est pas du tout celle qui est testée. Ce qui signifie que les tests de classe
ActualClassUnderTest
peuvent commencer à se casser car l'implémentation de aClassUsedAsMock
changé. Et cela m'envoie une odeur nauséabonde. Les tests pourActualClassUnderTest
ne devraient de préférence se casser que lors d'unActualClassUnderTest
changement.Je me rends compte qu'écrire des affirmations contre le faux est une pratique courante, surtout lorsque vous êtes un abonné TDD de type moqueur. Je suppose que je suis fermement avec Martin Fowler dans le camp classique (voir "Les moqueurs ne sont pas des talons" de Martin Fowler ) et, comme Osherove, évitez autant que possible les tests d'interaction (ce qui ne peut être fait qu'en affirmant contre les faux).
Pour une lecture amusante sur les raisons pour lesquelles vous devriez éviter les moqueries telles que définies ici, google pour "fowler mockist classicist". Vous trouverez une pléthore d'opinions.
la source
Comme mentionné dans la réponse la plus votée, Martin Fowler discute de ces distinctions dans les moqueries ne sont pas des talons , et en particulier le sous-titre The Difference Between Mocks and Stubs , alors assurez-vous de lire cet article.
Plutôt que de se concentrer sur la façon dont ces choses sont différentes, je pense qu'il est plus instructif de se concentrer sur la raison pour laquelle il s'agit de concepts distincts. Chacun existe dans un but différent.
Faux
Un faux est une implémentation qui se comporte "naturellement", mais n'est pas "réelle". Ce sont des concepts flous et donc différentes personnes ont des compréhensions différentes de ce qui rend les choses fausses.
Un exemple de faux est une base de données en mémoire (par exemple en utilisant sqlite avec le
:memory:
magasin). Vous ne l'utiliseriez jamais pour la production (car les données ne sont pas persistantes), mais c'est parfaitement adéquat comme base de données à utiliser dans un environnement de test. Il est également beaucoup plus léger qu'une "vraie" base de données.Comme autre exemple, vous utilisez peut-être une sorte de magasin d'objets (par exemple Amazon S3) en production, mais dans un test, vous pouvez simplement enregistrer des objets dans des fichiers sur le disque; alors votre implémentation "enregistrer sur disque" serait un faux. (Ou vous pouvez même simuler l'opération "enregistrer sur le disque" en utilisant un système de fichiers en mémoire à la place.)
Comme troisième exemple, imaginez un objet qui fournit une API de cache; un objet qui implémente la bonne interface mais qui n'effectue simplement pas de mise en cache mais renvoie toujours un échec de cache serait une sorte de faux.
Le but d'un faux n'est pas d'affecter le comportement du système testé , mais plutôt de simplifier l'implémentation du test (en supprimant les dépendances inutiles ou lourdes).
Bouts
UNE stub est une implémentation qui se comporte "de façon anormale". Il est préconfiguré (généralement par la configuration de test) pour répondre à des entrées spécifiques avec des sorties spécifiques.
Le but d'un stub est de faire tester votre système dans un état spécifique. Par exemple, si vous écrivez un test pour du code qui interagit avec une API REST, vous pouvez supprimer l'API REST avec une API qui renvoie toujours une réponse prédéfinie ou qui répond à une demande d'API avec une erreur spécifique. De cette façon, vous pourriez écrire des tests qui font des affirmations sur la façon dont le système réagit à ces états; par exemple, tester la réponse de vos utilisateurs si l'API renvoie une erreur 404.
Un stub est généralement implémenté pour ne répondre qu'aux interactions exactes auxquelles vous lui avez demandé de répondre. Mais la caractéristique clé qui fait de quelque chose un talon est son objectif : un stub consiste à configurer votre cas de test.
Se moquer
Une maquette est similaire à un stub, mais avec une vérification ajoutée. Le but d'une maquette est de faire des affirmations sur la façon dont votre système testé interagit avec la dépendance .
Par exemple, si vous écrivez un test pour un système qui télécharge des fichiers sur un site Web, vous pouvez créer une maquette qui accepte un fichier et que vous pouvez utiliser pour affirmer que le fichier téléchargé était correct. Ou, à plus petite échelle, il est courant d'utiliser une maquette d'un objet pour vérifier que le système testé appelle des méthodes spécifiques de l'objet simulé.
Les simulations sont liées aux tests d'interaction , qui est une méthodologie de test spécifique. Les personnes qui préfèrent tester l' état du système plutôt que les interactions système utiliseront les simulations avec modération, voire pas du tout.
Double test
Les contrefaçons, les talons et les simulacres appartiennent tous à la catégorie des doubles de test . Un double de test est tout objet ou système que vous utilisez dans un test au lieu de quelque chose d'autre. La plupart des tests de logiciels automatisés impliquent l'utilisation de tests doubles d'une sorte ou d'une autre. D'autres types de doubles de test comprennent des valeurs fictives , des espions , et E / S blackholes .
la source
Pour illustrer l'utilisation des talons et des maquettes, je voudrais également inclure un exemple basé sur « L'art des tests unitaires » de Roy Osherove .
Imaginez, nous avons une application LogAnalyzer qui a la seule fonctionnalité d'imprimer des journaux. Il doit non seulement parler à un service Web, mais si le service Web génère une erreur, LogAnalyzer doit consigner l'erreur dans une autre dépendance externe, en l'envoyant par e-mail à l'administrateur du service Web.
Voici la logique que nous aimerions tester dans LogAnalyzer:
Comment testez-vous que LogAnalyzer appelle correctement le service de messagerie lorsque le service Web lève une exception? Voici les questions auxquelles nous sommes confrontés:
Comment remplacer le service Web?
Comment pouvons-nous simuler une exception du service Web afin de pouvoir tester l'appel au service de messagerie?
Comment saurons-nous que le service de messagerie a été appelé correctement ou pas du tout?
Nous pouvons traiter les deux premières questions en utilisant un talon pour le service Web . Pour résoudre le troisième problème, nous pouvons utiliser un objet factice pour le service de messagerie .
Un faux est un terme générique qui peut être utilisé pour décrire un talon ou une maquette. Dans notre test, nous aurons deux faux. L'une sera la maquette du service de messagerie, que nous utiliserons pour vérifier que les paramètres corrects ont été envoyés au service de messagerie. L'autre sera un talon que nous utiliserons pour simuler une exception levée à partir du service Web. C'est un talon parce que nous n'utiliserons pas le faux service Web pour vérifier le résultat du test, uniquement pour nous assurer que le test fonctionne correctement. Le service de messagerie électronique est une maquette, car nous affirmerons qu'il a été appelé correctement.
la source
la chose que vous affirmez dessus est appelée un objet simulé et tout le reste qui a simplement aidé le test est un talon .
la source
Il s'agit de rendre les tests expressifs. Je mets des attentes sur une maquette si je veux que le test décrive une relation entre deux objets. Je stub renvoie des valeurs si je configure un objet de support pour m'amener au comportement intéressant dans le test.
la source
Si vous connaissez Arrange-Act-Assert, alors une façon d'expliquer la différence entre stub et mock qui pourrait vous être utile est que les stubs appartiennent à la section arrange, comme ils le sont pour organiser l'état d'entrée, et que les mocks appartiennent à la section assert comme ils le sont pour affirmer les résultats.
Les nuls ne font rien. Ils sont juste pour remplir des listes de paramètres, afin que vous n'obteniez pas d'erreurs indéfinies ou nulles. Ils existent également pour satisfaire le vérificateur de type dans des langages strictement typés, afin que vous puissiez être autorisé à compiler et à exécuter.
la source
Stub, Fakes et Mocks ont des significations différentes selon les différentes sources. Je vous suggère de présenter les termes internes de votre équipe et de vous mettre d'accord sur leur signification.
Je pense qu'il est important de distinguer deux approches: - la validation du comportement (implique une substitution de comportement) - la validation de l'état final (implique l'émulation du comportement)
Pensez à envoyer des e-mails en cas d'erreur. Lors de la validation du comportement - vous vérifiez que la méthode
Send
de aIEmailSender
été exécutée une fois. Et vous devez émuler le résultat de retour de cette méthode, renvoyer l'ID du message envoyé. Alors vous dites: "Je m'attends à ce queSend
soit appelé. Et je vais simplement renvoyer un identifiant factice (ou aléatoire) pour tout appel" . C'est la validation du comportement:emailSender.Expect(es=>es.Send(anyThing)).Return((subject,body) => "dummyId")
Lors de la validation de l'état, vous devrez créer
TestEmailSender
ces implémentationsIEmailSender
. Et implémentez laSend
méthode - en enregistrant l'entrée dans une structure de données qui sera utilisée pour la vérification de l'état futur comme un tableau de certains objetsSentEmails
, puis il teste que vous vérifierez queSentEmails
contient l'e-mail attendu. Il s'agit d'une validation d'état:Assert.AreEqual(1, emailSender.SentEmails.Count)
D'après mes lectures, j'ai compris que la validation du comportement s'appelait généralement Mocks . Et la validation Etat habituellement appelé Stubs ou Fakes .
la source
stub et fake sont des objets en ce sens qu'ils peuvent varier leur réponse en fonction des paramètres d'entrée. la principale différence entre eux est qu'un faux est plus proche d'une implémentation du monde réel qu'un stub. Les talons contiennent essentiellement des réponses codées en dur à une demande attendue. Voyons un exemple:
Une maquette est une étape par rapport aux contrefaçons et aux talons. Les maquettes offrent les mêmes fonctionnalités que les talons mais sont plus complexes. Ils peuvent avoir des règles définies pour eux qui dictent dans quel ordre les méthodes de leur API doivent être appelées. La plupart des simulateurs peuvent suivre le nombre de fois qu'une méthode a été appelée et peuvent réagir en fonction de ces informations. Les simulateurs connaissent généralement le contexte de chaque appel et peuvent réagir différemment selon les situations. Pour cette raison, les moqueries nécessitent une certaine connaissance de la classe dont elles se moquent. un stub ne peut généralement pas suivre le nombre de fois qu'une méthode a été appelée ou dans quel ordre une séquence de méthodes a été appelée. Une maquette ressemble à:
la source
fake object
est une véritable implémentation d'interface (protocole) ou une extension utilisant l'héritage ou d'autres approches qui peuvent être utilisées pour créer - est une dépendance. Habituellement, il est créé par le développeur comme une solution la plus simple pour remplacer une certaine dépendancestub object
est un objet nu (0, nil et méthodes sans logique) avec et supplémentaire et prédéfinie (par développeur) état pour définir des valeurs retournées. Habituellement, il est créé par le cadremock object
est très similaire àstub object
mais l' état supplémentaire est changé pendant l'exécution du programme pour vérifier si quelque chose s'est produit (la méthode a été appelée).la source