Question

Quel est le but de se moquer?

J'ai suivi des didacticiels ASP.NET MVC utilisant NUnit pour les tests et Moq pour les moqueries. Je suis cependant un peu incertain quant à la partie moqueuse de celle-ci.

Était-ce utile?

La solution

Le but de se moquer est de isoler la classe en cours de test des autres classes.

Ceci est utile quand une classe:

  • se connecte à une ressource externe (FileSystem, DB, réseau ...)
  • est coûteux à installer ou n'est pas encore disponible (matériel en cours de développement)
  • ralentit l'exécution des tests unitaires
  • a un comportement non déterministe
  • a (ou est) une interface utilisateur

Cela facilite également le test des conditions d'erreur, car vous construisez votre objet fictif pour qu'il retourne et erreur, lève une exception ...

Le modèle peut enregistrer la manière dont il a été appelé (ordre des appels de fonction, paramètres) et ceci peut être vérifié par le test. EDIT: Par exemple: La méthode que vous testez envoie un message, tel qu'un IPC. La méthode de l'objet fictif peut enregistrer combien de fois il a été appelé, le paramètre qu'il a reçu (c'est-à-dire le message à envoyer). Ensuite, le test peut interroger l'objet fictif et affirmer le nombre de messages envoyés, le contenu du message ... De même, l'objet fictif peut enregistrer les méthodes appelées dans une chaîne de journal et le test peut extraire cette chaîne et l'assert.

N'abusez pas des objets fictifs : testez le comportement plutôt que la mise en œuvre, sinon les tests unitaires seront trop étroitement couplés au code et fragiles (rupture du refactoring).

Mock peut être codé manuellement ou généré par un framework moqueur .

Autres conseils

Mocking vous permet d’isoler votre classe sous test de ses dépendances. Généralement, vous créez une maquette pour chaque dépendance de la classe sous test et configurez la maquette pour renvoyer les valeurs attendues. Vous fournissez ensuite la maquette à votre classe testée au lieu d'une copie réelle de la classe dont dépend votre classe testée. Vous pouvez ensuite utiliser le framework moqueur pour vérifier que les appels attendus ont été passés vers le ou les objets fictifs afin de vous assurer que votre classe sous test fonctionne correctement.

Il est conçu pour se moquer d’une instance individuelle à partir d’une collection de groupe. Beaucoup utilisé lors de rassemblements d'objets irréguliers.

Alors que se moquer est généralement compris comme permettant d'isoler une classe sous test, ce n'est pas le but principal d'une maquette (les moignons sont meilleurs pour cela). Au lieu de cela, nous devons regarder ce qui se passe lorsqu'un objet reçoit l'ordre de faire quelque chose qui est l'une des trois choses suivantes.

  1. Sortie directe - résultat d'un appel de méthode
  2. Modifications internes: modifications apportées à la classe lors d'un appel de méthode
  3. Sortie indirecte - le code sous test appelle une classe différente

Les tests basés sur les états concernent uniquement les no 1 et 2. N ° 1 via le résultat obtenu par la méthode. # 2 en accédant à l'état interne des objets.

Cela nous laisse avec le n ° 3 pour lequel nous pouvons prendre deux voies. La première consiste à utiliser une maquette et la seconde à utiliser un test d'espion. La principale différence est que, sur un simulacre, vous créez les attentes avant d'exécuter le code sous test, puis que le simulacre les vérifie après, alors qu'avec un test-test, vous exécutez le code sous test et demandez ensuite au test-test si certaines actions se sont produites.

Donc, pour résumer tout cela… quand vous pensez tester ce que fait une classe si vous avez besoin de tester une sortie indirecte (c'est-à-dire un appel à une autre classe), c'est là que Mocking entre en jeu.

Je commence à me moquer aussi, mais je vais tenter le coup. D'après mon expérience, se moquer a deux avantages principaux:

  • Vous pouvez commencer à utiliser des objets avant d'écrire réellement l'implémentation. Vous pouvez définir une interface et utiliser mocking pour utiliser l'interface dans des tests unitaires ou même du code.
  • Mocking vous permet d’isoler l’objet testé lors de tests unitaires. Avec les objets fictifs, vous pouvez contrôler complètement tous les objets avec lesquels l'objet à tester interagit, ce qui supprime les dépendances externes du test.

" Mock " est un terme très surchargé dans testing & amp; Cercles TDD. Voir l'article de Martin Fowler, se moque des talons . Un " bon " Mock sait quelles valeurs il est censé recevoir et vous permet de savoir quand il n'obtient pas ce qui était prévu. Cela vous permet de tester les interactions au lieu des tests d'état: vous vérifiez que la classe sous test transmet les bons messages à ses collaborateurs, dans le bon ordre. Les tests d'interaction sont assez différents des tests d'état conventionnels et peuvent être difficiles à comprendre. Garder à l’esprit que les tests d’interaction sont l’essentiel des simulacres peuvent en faciliter la compréhension.

Great Realtime Example of Mocking by Bert F

Unit Testing

Imagine unit testing for this system:

cook <- waiter <- customer

Its generally easy to envision testing a low-level component like the cook:

cook <- test driver

The test driver simply orders different dishes and verifies the cook returns the correct dish for each order.

Its harder to test a middle component, like the waiter, that utilizes the behavior of other components. A naive tester might test the waiter component the same way we tested the cook component:

cook <- waiter <- test driver

The test driver would order different dishes and ensure the waiter returns the correct dish. Unfortunately, that means that this test of the waiter component may be dependent on the correct behavior of the cook component. This dependency is even worse if the cook component has any test-unfriendly characteristics, like non-deterministic behavior (the menu includes chef's surprise as an dish), lots of dependencies (cook won't cook without his entire staff), or lot of resources (some dishes require expensive ingredients or take an hour to cook).

Since this a waiter test, ideally, we want to test just the waiter, not the cook. Specifically, we want to make sure the waiter conveys the customer's order to the cook correctly and delivers the cook's food to the customer correctly.

Unit testing means testing units independently, so a better approach would be to isolate the component under test (the waiter) using what Fowler calls test doubles (dummies, stubs, fakes, mocks).

    -----------------------
   |                       |
   v                       |
test cook <- waiter <- test driver

Here, the test cook is "in cahoots" with the test driver. Ideally, the system under test is designed so that the test cook can be easily substituted (injected) to work with the waiter without changing production code (e.g. without changing the waiter code).

Mock Objects

Now, the test cook (test double) could be implemented different ways:

  • a fake cook - a someone pretending to be a cook by using frozen dinners and a microwave,
  • a stub cook - a hot dog vendor that always gives you hot dogs no matter what you order, or
  • a mock cook - an undercover cop following a script pretending to be a cook in a sting operation.

See Fowler's article for the more specifics about fakes vs stubs vs mocks vs dummies, but for now, let's focus on a mock cook.

    -----------------------
   |                       |
   v                       |
mock cook <- waiter <- test driver

A big part of unit testing the waiter component focuses on how the waiter interacts with the cook component . A mock-based approach focuses on fully specifying what the correct interaction is and detecting when it goes awry.

The mock object knows in advance what is supposed to happen during the test (e.g. which of its methods calls will be invoked, etc.) and the mock object knows how it is supposed to react (e.g. what return value to provide). The mock will indicate whether what really happens differs from what is supposed to happen. A custom mock object could be coded for the expected behavior of each test case, but a mocking framework strives to allow such a behavior specification to be clearly and easily indicated directly in the test case.

The conversation surrounding a mock-based test might look like this:

test driver to mock cook: expect a hot dog order and give him this dummy hot dog in response

test driver (posing as customer) to waiter: I would like a hot dog please
waiter to mock cook: 1 hot dog please
mock cook to waiter: order up: 1 hot dog ready (gives dummy hot dog to waiter)
waiter to test driver: here is your hot dog (gives dummy hot dog to test driver)

test driver: TEST SUCCEEDED!

But since our waiter is new, this is what could happen:

test driver to mock cook: expect a hot dog order and give him this dummy hot dog in response

test driver (posing as customer) to waiter: I would like a hot dog please
waiter to mock cook: 1 hamburger please
mock cook stops the test: I was told to expect a hot dog order!

test driver notes the problem: TEST FAILED! - the waiter changed the order

or

test driver to mock cook: expect a hot dog order and give him this dummy hot dog in response

test driver (posing as customer) to waiter: I would like a hot dog please
waiter to mock cook: 1 hot dog please
mock cook to waiter: order up: 1 hot dog ready (gives dummy hot dog to waiter)
waiter to test driver: here is your french fries (gives french fries from some other order to test driver)

test driver notes the unexpected french fries: TEST FAILED! the waiter gave back wrong dish

It may be hard to clearly see the difference between mock objects and stubs without a contrasting stub-based example to go with this, but this answer is way too long already :-)

Also note that this is a pretty simplistic example and that mocking frameworks allow for some pretty sophisticated specifications of expected behavior from components to support comprehensive tests. There's plenty of material on mock objects and mocking frameworks for more information.

One other answer :

  • Stub = fake objects to be able to run your test without the entire real context

  • Mock = fake object to record the interaction of your component and verify theses interactions

You can have several stubs in one test but only one mock because if you have more than one mock you certainly test more than one feature (and it defeat the purpose of the test-one-thing principle).

To go beyond the basics, Mocks are more behavioral verification than the traditionnal state verification of the test where you check the state of your component after acting on it (Arrange,Act, Assert with Mocks it is more Arrange, Act, Verify) :

State verification Assert.AreEqual(valueExpected,mycomponent.Property); Behavioral verification : myMock.WasCalled(MyMethod);

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top