Quelle est la différence entre une maquette et un talon?


963

J'ai lu divers articles sur la moquerie contre le stubbing dans les tests, y compris les moqueries ne sont pas des talons de Martin Fowler , mais je ne comprends toujours pas la différence.



75
@OP Parce qu'il n'y a pas de différence. Cet article, autant aimé par la communauté, est - avec tout le respect que je vous dois - rendant tout inutile inutile déroutant en ajoutant un sens supplémentaire à des mots qui sont faciles à comprendre autrement et en rendant les choses inutiles compliquées. La simulation est juste une simulation, quelque chose qui exécute une fausse logique métier au lieu d'une vraie. La vérification du comportement à la fin est votre choix, mais c'est toujours une simulation. Ou comme vous voulez l'appeler, mais faites-en UN. Ne coupez pas les cheveux. Restez simple, afin que les gens puissent comprendre votre concept facilement - avec lequel l'article ci-dessus échoue.
2016

10
"La classification entre les faux, les faux et les talons est très incohérente dans la littérature." Avec de nombreuses citations. Encore une de mes citations préférées sur Wikipedia - si une telle chose existe :) en.wikipedia.org/wiki/Mock_object
JD.

11
que l'article de Martin Fowler est vraiment difficile à comprendre pour les débutants.
lmiguelvargasf

1
D'après ce que je comprends, un talon ne serait qu'un objet à jeter pour votre test, comme une collection de données factices. Un Mock serait une version intelligemment remplacée de quelque chose de plus complexe, comme une couche de service avec diverses méthodes, dont vous auriez pu changer le comportement, pour vos tests. Les deux choses sont utilisées ensemble, comme si vous pouviez passer des objets tronqués dans votre calque simulé.
JsonStatham

Réponses:


746

Talon

Je crois que la plus grande distinction est qu'un talon que vous avez déjà écrit avec un comportement prédéterminé. Ainsi, vous auriez une classe qui implémente la dépendance (classe abstraite ou interface la plus probable) que vous simulez à des fins de test et les méthodes seraient simplement tronquées avec des réponses définies. Ils ne feraient rien d'extraordinaire et vous auriez déjà écrit le code tronqué pour cela en dehors de votre test.

Moquer

Une maquette est quelque chose qui, dans le cadre de votre test, doit être configuré selon vos attentes. Une maquette n'est pas configurée d'une manière prédéterminée, vous avez donc du code qui le fait dans votre test. Les mocks d'une certaine manière sont déterminés lors de l'exécution, car le code qui définit les attentes doit s'exécuter avant de faire quoi que ce soit.

Différence entre les simulacres et les talons

Les tests écrits avec des initialize -> set expectations -> exercise -> verifysimulations suivent généralement un modèle de test. Alors que le talon pré-écrit suivrait un initialize -> exercise -> verify.

Similitude entre les simulacres et les talons

Le but des deux est d'éliminer le test de toutes les dépendances d'une classe ou d'une fonction afin que vos tests soient plus ciblés et plus simples dans ce qu'ils essaient de prouver.


876

Préface

Il existe plusieurs définitions d'objets, qui ne sont pas réelles. Le terme général est test double . Ce terme englobe: mannequin , faux , talon , faux .

Référence

Selon l'article de Martin Fowler :

  • Les objets factices sont transmis mais jamais réellement utilisés. Habituellement, ils sont juste utilisés pour remplir des listes de paramètres.
  • Les faux objets ont en fait des implémentations fonctionnelles, mais prennent généralement un raccourci qui les rend impropres à la production (une base de données en mémoire est un bon exemple).
  • 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.

Style

Mocks vs Stubs = Test comportemental vs test d'état

Principe

Selon le principe du test, une seule chose par test , il peut y avoir plusieurs talons dans un test, mais généralement il n'y a qu'une seule maquette.

Cycle de la vie

Testez le cycle de vie avec des talons:

  1. Configuration - Préparez l'objet qui est testé et ses collaborateurs de stubs.
  2. Exercice - Testez la fonctionnalité.
  3. Vérifier l'état - Utilisez les assertions pour vérifier l'état de l'objet.
  4. Teardown - Nettoyez les ressources.

Testez le cycle de vie avec des simulacres:

  1. Données de configuration - Préparez l'objet en cours de test.
  2. Configuration des attentes - Préparez les attentes dans la maquette utilisée par l'objet principal.
  3. Exercice - Testez la fonctionnalité.
  4. Vérifiez les attentes - Vérifiez que les méthodes correctes ont été invoquées dans la simulation.
  5. Vérifier l'état - Utilisez les assertions pour vérifier l'état de l'objet.
  6. Teardown - Nettoyez les ressources.

Sommaire

Les tests de mocks et de stubs donnent une réponse à la question: quel est le résultat?

Les tests avec des simulations sont également intéressés par: Comment le résultat a-t-il été obtenu?


Attendez, les simulacres retournent également des réponses en conserve? Parce que sinon pourquoi répondent-ils à la question?
AturSams

D'après ce que vous avez écrit, je peux dire que mocks = stubs + attentes et vérifications, car les mocks "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" (comme les stubs). Et l'exemple que Fowler a montré comme exemple de talon est en fait l'exemple d'un espion! Cela signifie qu'une maquette est un talon et qu'un espion est un talon. Et un stub est juste un objet qui a plusieurs méthodes de travail. Cela explique également pourquoi la méthode stub () obsolète de Mockito.
kolobok

Ce que je trouve déroutant là-dessus et la réponse acceptée est ce «cadre d'attente», qu'est-ce que cela signifie même? Habituellement, dans le «code principal», vous créez les résultats que vous attendez. Il semble que vous ayez mis les attentes d'une manière ou d'une autre dans l'objet factice, ce qui n'a pas de sens pour moi. AUSSI, vous pouvez tout aussi facilement exercer la simulation avec une certaine entrée, stocker le résultat, créer plus tard «les attentes» et ensuite comparer. Vous utilisez une terminologie que je trouve trop abstraite et ambiguë.
IceFire

365

Un talon est un simple faux objet. Il s'assure simplement que le test se déroule correctement.
Une maquette est un talon plus intelligent. Vous vérifiez que votre test le traverse.


33
Je pense que c'est la réponse la plus succincte et la plus précise. À emporter: un faux moignon IS-A. stackoverflow.com/a/17810004/2288628 est la version longue de cette réponse.
PoweredByRice

8
Je ne pense pas qu'une maquette soit un talon. Les maquettes sont utilisées pour affirmer et ne doivent jamais renvoyer de données, les talons sont utilisés pour renvoyer des données et ne doivent jamais affirmer.
dave1010

2
@ dave1010 Mocks peut très certainement renvoyer des données ou même lever une exception. Ils devraient le faire en réponse aux params qui leur ont été transmis.
Trenton

2
@trenton si un objet revient ou jette sur la base des données transmises, alors c'est un faux , pas une maquette. Les talons testent la façon dont votre SUT gère la réception des messages, les simulateurs testent la façon dont votre SUT envoie les messages. Mélanger les 2 est susceptible de conduire à une mauvaise conception OO.
dave1010

8
Je pense que c'est génial - un talon renvoie les réponses aux questions. Une maquette renvoie également des réponses aux questions (est un talon) mais elle vérifie également que la question a été posée !!
Leif

238

Voici une description de chacun suivi d'un échantillon du monde réel.

  • Factice - juste de fausses valeurs pour satisfaire le API.

    Exemple : Si vous testez une méthode d'une classe qui nécessite de nombreux paramètres obligatoires dans un constructeur qui n'ont aucun effet sur votre test, vous pouvez créer des objets factices dans le but de créer de nouvelles instances d'une classe.

  • Fake - crée une implémentation de test d'une classe qui peut dépendre d'une infrastructure externe. (Il est recommandé que votre test unitaire n'interagisse PAS réellement avec l'infrastructure externe.)

    Exemple : créez une fausse implémentation pour accéder à une base de données, remplacez-la par une in-memorycollection.

  • Stub - substitue des méthodes pour renvoyer des valeurs codées en dur, également appelées state-based.

    Exemple : votre classe de test dépend d'une méthode qui Calculate()prend 5 minutes. Plutôt que d'attendre 5 minutes, vous pouvez remplacer sa véritable implémentation par un stub qui renvoie des valeurs codées en dur; ne prenant qu'une petite fraction du temps.

  • Mock - très similaire Stubmais interaction-basedbasé sur un état. Cela signifie que vous ne vous attendez pas Mockà renvoyer une valeur, mais à supposer que l'ordre spécifique des appels de méthode est effectué.

    Exemple: vous testez une classe d'enregistrement d'utilisateurs. Après avoir appelé Save, il devrait appeler SendConfirmationEmail.

Stubset Mockssont en fait des sous-types de Mock, à la fois échanger une implémentation réelle avec une implémentation de test, mais pour des raisons différentes et spécifiques.


175

Dans le cours codeschool.com , Rails Testing for Zombies , ils donnent cette définition des termes:

Talon

Pour remplacer une méthode par du code qui renvoie un résultat spécifié.

Moquer

Un stub avec une affirmation que la méthode est appelée.

Ainsi, comme Sean Copenhaver l'a décrit dans sa réponse, la différence est que les simulacres établissent des attentes (c'est-à-dire qu'ils font des affirmations, à savoir si ou comment ils sont appelés).


Pour compléter le post Dillon, pensez-y, vous avez une classe appelée "MakeACake" qui prend plusieurs bibliothèques: Milk, Eggs, Sugar, Oven.
aarkerio

139

Les talons n'échouent pas à vos tests, la maquette peut.


2
Et je pense que c'est bien, vous savez si les tests ont le même comportement après refactoring.
RodriKing

1
@RodriKing J'ai le même sentiment. Comme avec Mock, avec toute modification du code de production - vous avez des modifications correspondantes au code de test. Quelle douleur! Avec Stubs, vous avez l'impression de continuer à tester le comportement, donc aucune modification micro n'a besoin d'être effectuée avec le code de test.
tucq88

35

Je pense que la réponse la plus simple et la plus claire à cette question est donnée par Roy Osherove dans son livre The art of Unit Testing (page 85)

La façon la plus simple de savoir que nous avons affaire à un talon est de remarquer que le talon ne peut jamais échouer au test. Les assertions que le test utilise sont toujours contre la classe testée.

D'un autre côté, le test utilisera un objet factice pour vérifier si le test a échoué ou non. [...]

Encore une fois, l'objet factice est l'objet que nous utilisons pour voir si le test a échoué ou non.

Cela signifie que si vous faites des affirmations contre le faux, cela signifie que vous utilisez le faux comme une maquette, si vous utilisez le faux uniquement pour exécuter le test sans affirmation, vous utilisez le faux comme talon.


2
Je souhaite que votre réponse trouve son chemin vers le haut. Voici R. Osherove expliquant ce youtu.be/fAb_OnooCsQ?t=1006 .
Michael Ekoka

31

En lisant toutes les explications ci-dessus, permettez-moi d'essayer de condenser:

  • Stub : un morceau de code factice qui permet l'exécution du test, mais peu vous importe ce qui lui arrive.
  • Mock : un morceau de code factice, que vous VERIFIEZ est appelé correctement dans le cadre du test.
  • Spy : un morceau de code factice, qui intercepte certains appels vers un vrai morceau de code, vous permettant de vérifier les appels sans remplacer tout l'objet d'origine.

4
Bonne réponse. Mock semble assez similaire à Spy, en fonction de votre définition. Ce serait bien si vous mettiez à jour votre réponse pour inclure quelques tests supplémentaires en double.
Rowan Gontier

Je n'avais pas entendu parler de Spy lorsque j'ai écrit cette réponse.
O'Rooney

23

Un Mock teste simplement le comportement, en s'assurant que certaines méthodes sont appelées. Un Stub est une version testable (en soi) d'un objet particulier.

Que voulez-vous dire par Apple?


19
"Que voulez-vous dire par Apple?" Utilisez Helvetica
kubi

7
À la manière d'Apple plutôt qu'à Microsoft :)
never_had_a_name

2
Est-ce que cela aide la situation?
NebulaFox

21

Si vous le comparez au débogage:

Stub, c'est comme s'assurer qu'une méthode retourne la valeur correcte

Mock, c'est comme entrer dans la méthode et s'assurer que tout ce qui se trouve à l'intérieur est correct avant de retourner la valeur correcte.


20

L'utilisation d'un modèle mental m'a vraiment aidé à comprendre cela, plutôt que toutes les explications et articles, qui ne «s'enfonçaient» pas tout à fait.

Imaginez que votre enfant a une plaque de verre sur la table et qu'il commence à jouer avec. Maintenant, vous avez peur que ça se casse. Alors, donnez-lui plutôt une assiette en plastique. Ce serait un Mock (même comportement, même interface, implémentation "plus douce").

Maintenant, disons que vous n'avez pas le remplacement en plastique, alors vous expliquez "Si vous continuez à jouer avec, il se cassera!". C'est un bout , vous avez fourni un état prédéfini à l'avance.

Un mannequin serait la fourchette qu'il n'utilisait même pas ... et un espion pourrait être quelque chose comme fournir la même explication que vous avez déjà utilisée qui fonctionnait.


19

Je pense que la différence la plus importante entre eux est leurs intentions.

Permettez-moi d'essayer de l'expliquer dans POURQUOI talon vs POURQUOI maquette

Supposons que j'écris du code de test pour le contrôleur de chronologie publique de mon client mac twitter

Voici un exemple de code de test

twitter_api.stub(:public_timeline).and_return(public_timeline_array)
client_ui.should_receive(:insert_timeline_above).with(public_timeline_array)
controller.refresh_public_timeline
  • STUB: La connexion réseau à l'API Twitter est très lente, ce qui rend mon test lent. Je sais que cela renverra des délais, j'ai donc créé un talon simulant l'API HTTP Twitter, afin que mon test l'exécute très rapidement et que je puisse exécuter le test même si je suis hors ligne.
  • MOCK: Je n'ai encore écrit aucune de mes méthodes d'interface utilisateur, et je ne sais pas quelles méthodes j'ai besoin d'écrire pour mon objet d'interface utilisateur. J'espère savoir comment mon contrôleur collaborera avec mon objet ui en écrivant le code de test.

En écrivant mock, vous découvrez la relation de collaboration des objets en vérifiant que les attentes sont satisfaites, tandis que stub ne simule que le comportement de l'objet.

Je suggère de lire cet article si vous essayez d'en savoir plus sur les simulacres: http://jmock.org/oopsla2004.pdf


1
Je pense que vous avez la bonne idée, mais Dillon Kearns l'a expliqué beaucoup plus clairement.
O'Rooney

19

Pour être très clair et pratique:

Stub: une classe ou un objet qui implémente les méthodes de la classe / de l'objet à falsifier et renvoie toujours ce que vous voulez.

Exemple en JavaScript:

var Stub = {
   method_a: function(param_a, param_b){
      return 'This is an static result';
   }
}

Mock: Identique à stub, mais il ajoute une logique qui "vérifie" lorsqu'une méthode est appelée afin que vous puissiez être sûr qu'une implémentation appelle cette méthode.

Comme le dit @mLevan, imaginez comme exemple que vous testez une classe d'enregistrement d'utilisateurs. Après avoir appelé Save, il doit appeler SendConfirmationEmail.

Un code très stupide Exemple:

var Mock = {
   calls: {
      method_a: 0
   }

   method_a: function(param_a, param_b){
     this.method_a++; 
     console.log('Mock.method_a its been called!');
   }
}

16

Cette diapositive explique très bien les principales différences.

entrez la description de l'image ici

* Extrait de la conférence 16 du CSE 403, Université de Washington (diapositive créée par "Marty Stepp")


C'est l'explication la plus claire de la différence entre les deux, l'OMI. Pour le talon: le testeur prend le talon et l'utilise directement dans la classe sous test. Mais pour Mock, le testeur doit déterminer la manière dont l'objet Mock sera utilisé. Dans différents cas, il se comportera différemment. En revanche, le talon ne devrait pas se comporter différemment mais est utilisé tel quel (ce qui signifie renvoyer les mêmes données chaque fois qu'il est contacté)
Dexter

12

J'aime l'explication donnée par Roy Osherove [lien vidéo] .

Chaque classe ou objet créé est un faux. Il s'agit d'une simulation si vous vérifiez les appels par rapport à elle. Sinon, c'est un talon.


12
  • Stubs vs Mocks
    • Bouts
      1. fournir des réponses spécifiques aux appels de méthodes
        • ex: myStubbedService.getValues ​​() renvoie simplement une chaîne requise par le code testé
      2. utilisé par le code sous test pour l'isoler
      3. ne peut pas échouer au test
        • ex: myStubbedService.getValues ​​() renvoie simplement la valeur tronquée
      4. implémentent souvent des méthodes abstraites
    • Se moquer
      1. "surensemble" de talons; peut affirmer que certaines méthodes sont appelées
        • ex: vérifiez que myMockedService.getValues ​​() n'est appelé qu'une seule fois
      2. utilisé pour tester le comportement du code testé
      3. peut échouer au test
        • ex: vérifiez que myMockedService.getValues ​​() a été appelé une fois; la vérification échoue, car myMockedService.getValues ​​() n'a pas été appelé par mon code testé
      4. se moque souvent des interfaces

11

voyons Test Doubles:

  • Faux : les faux sont des objets qui ont des implémentations fonctionnelles, mais pas les mêmes que ceux de production. Tels que : implémentation en mémoire de Data Access Object ou Repository.
  • Stub : Stub est un objet qui contient des données prédéfinies et les utilise pour répondre aux appels pendant les tests. Tels que : un objet qui doit récupérer des données de la base de données pour répondre à un appel de méthode.

  • Mocks : les Mocks sont des objets qui enregistrent les appels qu'ils reçoivent. Dans l'assertion de test, nous pouvons vérifier sur Mocks que toutes les actions attendues ont été effectuées. Tels que : une fonctionnalité qui appelle le service d'envoi d'e-mails. pour en savoir plus, vérifiez ceci .


1
meilleure réponse à mon avis
Ero Stefano

9

Un faux est un terme générique qui peut être utilisé pour décrire soit un stub soit un faux objet (manuscrit ou autre), car ils ressemblent tous les deux au vrai objet.

Le fait qu'un faux soit un talon ou une maquette dépend de la façon dont il est utilisé dans le test actuel. S'il est utilisé pour vérifier une interaction (contre laquelle il est affirmé), il s'agit d'un objet factice. Sinon, c'est un talon.

Fakes garantit le bon déroulement du test. Cela signifie que le lecteur de votre futur test comprendra quel sera le comportement du faux objet, sans avoir besoin de lire son code source (sans avoir besoin de dépendre de ressources externes).

Que signifie le bon déroulement du test?
Par exemple dans le code ci-dessous:

 public void Analyze(string filename)
        {
            if(filename.Length<8)
            {
                try
                {
                    errorService.LogError("long file entered named:" + filename);
                }
                catch (Exception e)
                {
                    mailService.SendEMail("admin@hotmail.com", "ErrorOnWebService", "someerror");
                }
            }
        }

Vous souhaitez tester la méthode mailService.SendEMail () , pour ce faire, vous devez simuler une exception dans votre méthode de test, il vous suffit donc de créer une classe Fake Stub errorService pour simuler ce résultat, puis votre code de test pourra tester méthode mailService.SendEMail (). Comme vous le voyez, vous devez simuler un résultat provenant d'une autre classe External Dependency ErrorService.


8

Dès le papier Mock Roles, pas Objects , par les développeurs de jMock:

Les stubs sont des implémentations factices du code de production qui renvoient des résultats prédéfinis. Les objets fantômes agissent comme des talons, mais incluent également des assertions pour instrumenter les interactions de l'objet cible avec ses voisins.

Ainsi, les principales différences sont:

  • les attentes définies sur les talons sont généralement génériques, tandis que les attentes définies sur les simulations peuvent être plus "intelligentes" (par exemple, renvoyez-la au premier appel, au deuxième, etc.).
  • les stubs sont principalement utilisés pour configurer les entrées indirectes du SUT , tandis que les mocks peuvent être utilisés pour tester à la fois les entrées indirectes et les sorties indirectes du SUT.

Pour résumer, tout en essayant de dissiper la confusion du titre de l' article de Fowler : les simulacres sont des talons, mais ce ne sont pas seulement des talons .


1
Je pense que vous avez raison, mais c'est pourquoi l'article Fowler prête à confusion, le titre de l'article est "Les moqueurs ne sont pas des talons" ... mais ils le sont?! ¯_ (ツ) _ / ¯
stonedauwg

@stonedauwg, en effet, j'ai édité mon message pour incorporer votre jeu de mots et une clarification. J'espère que cela vous aidera un peu plus.
Dimos

@stonedauwg, une maquette n'est pas un talon, tout comme un rectangle n'est pas un carré. :)
seanriordan08

7

Je lisais L'art des tests unitaires et suis tombé sur la définition suivante:

Un faux est un terme générique qui peut être utilisé pour décrire soit un stub soit un faux objet (manuscrit ou autre), car ils ressemblent tous les deux au vrai objet. Le fait qu'un faux soit un talon ou une maquette dépend de la façon dont il est utilisé dans le test actuel. s'il est utilisé pour vérifier une interaction (contre laquelle il est affirmé), c'est un objet factice . Sinon, c'est un talon .


5

Je suis tombé sur cet article intéressant d'UncleBob The Little Mocker . Il explique toute la terminologie d'une manière très facile à comprendre, donc c'est utile pour les débutants. L'article de Martin Fowlers est difficile à lire, surtout pour les débutants comme moi.


4

Talon nous aide à exécuter le test. Comment? Il donne des valeurs qui aident à exécuter le test. Ces valeurs ne sont pas elles-mêmes réelles et nous avons créé ces valeurs juste pour exécuter le test. Par exemple, nous créons un HashMap pour nous donner des valeurs similaires aux valeurs de la table de base de données. Ainsi, au lieu d'interagir directement avec la base de données, nous interagissons avec Hashmap.

Mock est un faux objet qui exécute le test. où nous mettons assert.


"Donc, au lieu d'interagir directement avec la base de données, nous interagissons avec Hashmap." ... car nous n'avions pas encore le temps de coder le module de base de données, et nous ne pouvions pas exécuter le code de test sans utiliser le stub. Sinon, le même Hasmap serait une maquette! droite?
Boris Däppen

4

Voir ci-dessous un exemple de simulations vs stubs utilisant le framework C # et Moq. Moq n'a pas de mot clé spécial pour Stub mais vous pouvez également utiliser l'objet Mock pour créer des stubs.

namespace UnitTestProject2
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Moq;
    [TestClass]
    public class UnitTest1
    {
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method calls Repository GetName method "once" when Id is greater than Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));

            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Once);
        }
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method doesn't call Repository GetName method when Id is Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(0);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Never);
        }
        /// <summary>
        /// Test using Stub to Verify that GetNameWithPrefix method returns Name with a Prefix
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix()
        {
            // Arrange 
            var stubEntityRepository = new Mock<IEntityRepository>();
            stubEntityRepository.Setup(m => m.GetName(It.IsAny<int>()))
                .Returns("Stub");
            const string EXPECTED_NAME_WITH_PREFIX = "Mr. Stub";
            var entity = new EntityClass(stubEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            Assert.AreEqual(EXPECTED_NAME_WITH_PREFIX, name);
        }
    }
    public class EntityClass
    {
        private IEntityRepository _entityRepository;
        public EntityClass(IEntityRepository entityRepository)
        {
            this._entityRepository = entityRepository;
        }
        public string Name { get; set; }
        public string GetNameWithPrefix(int id)
        {
            string name = string.Empty;
            if (id > 0)
            {
                name = this._entityRepository.GetName(id);
            }
            return "Mr. " + name;
        }
    }
    public interface IEntityRepository
    {
        string GetName(int id);
    }
    public class EntityRepository:IEntityRepository
    {
        public string GetName(int id)
        {
            // Code to connect to DB and get name based on Id
            return "NameFromDb";
        }
    }
}

4

Point de vue des tests de Stub and Mock:

  • Stub est une implémentation factice effectuée par l'utilisateur de manière statique , c'est-à-dire que Stub écrit le code d'implémentation. Il ne peut donc pas gérer la définition de service et la condition dynamique. Normalement, cela se fait dans le cadre JUnit sans utiliser le cadre de simulation.

  • Mock est également une implémentation factice, mais son implémentation est effectuée de manière dynamique en utilisant des frameworks Mocking comme Mockito. Nous pouvons donc gérer la définition des conditions et des services de manière dynamique, c'est-à-dire que les mocks peuvent être créés dynamiquement à partir du code lors de l'exécution. Donc, en utilisant mock, nous pouvons implémenter Stubs dynamiquement.


3

Plus des réponses utiles, l'un des points les plus puissants de l'utilisation de Mocks than Subs

Si le collaborateur [dont le code principal en dépend] n'est pas sous notre contrôle (par exemple à partir d'une bibliothèque tierce),
dans ce cas, le stub est plus difficile à écrire qu'à se moquer .


2

J'ai utilisé des exemples de python dans ma réponse pour illustrer les différences.

Stub - Stubbing est une technique de développement logiciel utilisée pour implémenter des méthodes de classes au début du cycle de vie du développement. Ils sont couramment utilisés comme espaces réservés pour l'implémentation d'une interface connue, où l'interface est finalisée ou connue mais l'implémentation n'est pas encore connue ou finalisée. Vous commencez avec des stubs, ce qui signifie simplement que vous écrivez uniquement la définition d'une fonction et laissez le code réel pour plus tard. L'avantage est que vous n'oublierez pas les méthodes et que vous pourrez continuer à penser à votre design tout en le voyant dans le code. Vous pouvez également demander à votre talon de renvoyer une réponse statique afin que la réponse puisse être utilisée par d'autres parties de votre code immédiatement. Les objets stub fournissent une réponse valide, mais c'est statique, quelle que soit l'entrée que vous transmettez, vous obtiendrez toujours la même réponse:

class Foo(object):
    def bar1(self):
        pass

    def bar2(self):
        #or ...
        raise NotImplementedError

    def bar3(self):
        #or return dummy data
        return "Dummy Data"

Moquer objets sont utilisés dans les scénarios de test fictifs, ils valident que certaines méthodes sont appelées sur ces objets. Les objets fantaisie sont des objets simulés qui imitent le comportement d'objets réels de manière contrôlée. Vous créez généralement un objet factice pour tester le comportement d'un autre objet. Les simulations nous permettent de simuler des ressources qui ne sont pas disponibles ou trop lourdes pour les tests unitaires.

mymodule.py:

import os
import os.path

def rm(filename):
    if os.path.isfile(filename):
        os.remove(filename)

test.py:

from mymodule import rm
import mock
import unittest

class RmTestCase(unittest.TestCase):
    @mock.patch('mymodule.os')
    def test_rm(self, mock_os):
        rm("any path")
        # test that rm called os.remove with the right parameters
        mock_os.remove.assert_called_with("any path")

if __name__ == '__main__':
    unittest.main()

Il s'agit d'un exemple très basique qui exécute simplement rm et affirme le paramètre avec lequel il a été appelé. Vous pouvez utiliser une maquette avec des objets non seulement des fonctions comme indiqué ici, et vous pouvez également renvoyer une valeur afin qu'un objet maquette puisse être utilisé pour remplacer un stub pour le test.

Plus sur unittest.mock , notez qu'en python 2.x, le mock n'est pas inclus dans unittest mais est un module téléchargeable qui peut être téléchargé via pip (pip install mock).

J'ai également lu "The Art of Unit Testing" de Roy Osherove et je pense que ce serait génial si un livre similaire était écrit en utilisant des exemples Python et Python. Si quelqu'un connaît un tel livre, merci de le partager. À votre santé :)


2

Un stub est un faux objet construit à des fins de test. Une maquette est un talon qui enregistre si les appels attendus se sont effectivement produits.


2

Un stub est une fonction vide qui est utilisée pour éviter les exceptions non gérées pendant les tests:

function foo(){}

Une maquette est une fonction artificielle utilisée pour éviter les dépendances du système d'exploitation, de l'environnement ou du matériel pendant les tests:

function foo(bar){ window = this; return window.toString(bar); }

En termes d'affirmations et d'état:

  • Les simulations sont affirmées avant un événement ou un changement d'état
  • Les stubs ne sont pas affirmés, ils fournissent un état avant un événement pour éviter d'exécuter du code à partir d'unités non liées
  • Les espions sont configurés comme des talons, puis revendiqués après un événement ou un changement d'état
  • Les contrefaçons ne sont pas affirmées, elles s'exécutent après un événement avec des dépendances codées en dur pour éviter l'état

Références


2
+1 pour ajouter des espions au glossaire. De plus, je pense que vous voulez dire "Les espions sont configurés comme des simulacres" et non "Les espions sont configurés comme des talons"
Sameh Deabes


2

Une maquette est à la fois un objet technique et fonctionnel .

La maquette est technique . Il est en effet créé par une bibliothèque fictive (EasyMock, JMockit et plus récemment Mockito sont connus pour ceux-ci) grâce à la génération de code octet .
L'implémentation fictive est générée de manière à pouvoir l' instrumenter pour renvoyer une valeur spécifique lorsqu'une méthode est invoquée, mais aussi d'autres choses telles que la vérification qu'une méthode fictive a été invoquée avec certains paramètres spécifiques (contrôle strict) ou quels que soient les paramètres ( pas de contrôle strict).

Instanciation d'une simulation:

@Mock Foo fooMock

Enregistrer un comportement:

when(fooMock.hello()).thenReturn("hello you!");

Vérification d'une invocation:

verify(fooMock).hello()

Ce n'est clairement pas le moyen naturel d'instancier / remplacer la classe / le comportement Foo. C'est pourquoi je me réfère à un aspect technique.

Mais la maquette est également fonctionnelle car c'est une instance de la classe que nous devons isoler du SUT. Et avec des comportements enregistrés dessus, nous pourrions l'utiliser dans le SUT de la même manière que nous le ferions avec un talon.


Le stub n'est qu'un objet fonctionnel : c'est une instance de la classe que nous devons isoler du SUT et c'est tout. Cela signifie que la classe de stub et tous les agencements de comportements nécessaires lors de nos tests unitaires doivent être définis explicitement.
Par exemple, pour stub, hello()il faudrait sous- Fooclasser la classe (ou implémenter son interface, il l'a) et remplacer hello() :

public class HelloStub extends Hello{    
  public String hello { 
      return "hello you!"; 
  }
}

Si un autre scénario de test nécessite un autre retour de valeur, nous aurions probablement besoin de définir une manière générique de définir le retour:

public class HelloStub extends Hello{    
  public HelloStub(String helloReturn){
       this.helloReturn = helloReturn;
  }
  public String hello { 
      return helloReturn; 
  }
}

Autre scénario: si j'avais une méthode d'effet secondaire (pas de retour) et que je vérifierais que cette méthode a été invoquée, j'aurais probablement dû ajouter un booléen ou un compteur dans la classe stub pour compter combien de fois la méthode a été invoquée.


Conclusion

Le stub nécessite souvent beaucoup de surcharge / code pour écrire pour votre test unitaire. Ce que la simulation empêche grâce aux fonctionnalités d'enregistrement / de vérification prêtes à l'emploi.
C'est pourquoi de nos jours, l'approche stub est rarement utilisée dans la pratique avec l'avènement d'excellentes bibliothèques fictives.


À propos de l'article de Martin Fowler: Je ne pense pas être un programmeur "moqueur" lorsque j'utilise des simulacres et j'évite les talons.
Mais j'utilise la simulation quand c'est vraiment nécessaire (dépendances gênantes) et je privilégie les tests de découpage et les tests de mini-intégration lorsque je teste une classe avec des dépendances dont la simulation serait une surcharge.

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.