Dans les tests unitaires, pourquoi créer deux fois un référentiel?


10

L'autre jour, je lisais un peu sur les tests unitaires et j'ai vu des exemples où les gens créent une interface de référentiel (c'est-à-dire IExampleRepository) puis créent le vrai référentiel ( public class ExampleRepository : IExampleRepository) et un référentiel à utiliser pour les tests unitaires ( FakeExampleRepository : IExampleRepository).

Dans le, IExampleRepositoryils implémentaient les mêmes méthodes que dans le ExampleRepository, mais avec des requêtes Linq différentes.

Quel est exactement l'objectif ici? Je pensais qu'une partie des tests unitaires de votre code est de s'assurer qu'une méthode fonctionne correctement? Mais lorsque j'utilise deux requêtes totalement différentes, une pour «réelle» et une dans le test, quel sens a le test?

Réponses:


8

L'un des objectifs des tests unitaires est de tester une seule chose à la fois, c'est-à-dire une seule classe et une seule méthode. Si le référentiel lui-même n'est pas en cours de test, vous devriez normalement vous en moquer d'une certaine manière afin de simplement tester la logique de votre méthode / classe.

Cela dit, vous devez également tester avec un référentiel «réel» *, mais cela se ferait normalement dans un test d'intégration / système

* évidemment réel comme dans le référentiel mis en place pour le test, espérons pas par exemple la base de données de production.


Donc, dans les tests unitaires, je ne testerai pas la méthode elle-même pour m'assurer qu'elle renvoie les valeurs correctes (basées sur un ensemble de données factices / simulées)?
jao

oui, vous testerez la méthode elle-même, mais seul le code de la méthode, le code dans d'autres objets devrait être couvert dans d'autres tests unitaires, l'interaction de plusieurs objets devrait être couverte dans des tests d'intégration ou des tests de niveau supérieur
jk.

1
Ok, donc si je comprends bien, je devrais utiliser le référentiel d'origine lors des tests unitaires des référentiels. Je n'ai pas besoin de les tester lorsque j'écris des tests unitaires pour les contrôleurs (dans le cas d'Asp.Net MVC)
jao

4
@Theomax Dépend du contexte: si vous testez un composant logiciel qui n'est pas le vôtre ExampleRepository, il est préférable d'utiliser une maquette. La justification étant que vous ne testez pas le référentiel, mais autre chose.
Andres F.

5
@Theomax Pour développer le commentaire d'AndresF.: Si vous effectuez des tests unitaires ExampleRepository, utilisez la vraie chose. Si vous êtes des tests unitaires RepositoryController, il doit seulement utiliser une FakeExampleRepositoryqui renvoie des valeurs pré-spécifiées. De cette façon, si un bogue se glisse dans ExampleRepository, seul ce test unitaire échouera - RepositoryControllerles tests de continueront à réussir, donc vous savez qu'il n'y a pas de bogue là-bas. Si le contrôleur utilisait le vrai référentiel, ils échoueraient tous les deux et vous ne sauriez pas si vous aviez 1 bogue ou 2.
Izkata

5

Je suis d'accord avec les deux réponses de jk. et Jan Hudec - ils donnent de très bonnes informations. Mais j'ai pensé ajouter un peu.

Votre première question ("Quel est exactement l'objectif ici?") Est importante. Dans le cas que vous décrivez, le véritable objectif est de tester les classes qui utilisent l' IExampleRepositoryinterface, pas de tester les implémentations du référentiel. La création de FakeExampleRepositoryvous permet de tester ces classes client sans vous soucier des détails de la classe de référentiel réelle.

Cela est particulièrement vrai si l'objet que vous essayez de configurer rend les tests difficiles (par exemple, accède au système de fichiers, appelle un service Web ou parle à une base de données). En utilisant des interfaces (et d'autres techniques de ce type), vous maintenez le couplage bas. Par conséquent, la classe Xn'a besoin que de connaître l'interface et n'a pas besoin de connaître les détails de l'implémentation. Le but est de s'assurer que la classe Xfait la bonne chose.

La moquerie (ou le stubbing, le truquage ... il y a des différences nuancées) est un outil puissant pour les tests unitaires et TDD. Mais il peut être difficile de créer et de maintenir manuellement ces implémentations. Par conséquent, la plupart des langues ont maintenant des bibliothèques de simulation pour vous aider. Puisque vous utilisez C #, je recommanderais Moq car il est simple et très puissant. Ensuite, vous pouvez tester l'interface sans empiler de code supplémentaire pour les implémentations fictives.


the real objective is to test the classes that are utilizing the IExampleRepository interfacece n'est pas strictement vrai. L'objectif est de le tester indépendamment du IExampleRepository. +1 pour avoir recommandé un bon cadre d'isolement.
StuperUser

1
Je ne suis pas d'accord. Ce n'est pas indépendant du IExampleRepositorycar la classe testée est couplée à cette interface. Mais il est indépendant de toute implémentation de l'interface. Je dois admettre que mon explication pourrait probablement utiliser un peu plus de finesse. :)
Allan

5

Quel est exactement l'objectif ici?

Isolement.

L'idée d'une unité le teste pour tester la plus petite unité de code possible . Vous faites cela en l' isolant de tout autre code de production dans le test.

En créant de fausses classes, le seul code de production est la classe testée.

Si vous créez correctement un faux référentiel et que le test échoue, vous savez que le problème vient du code en cours de test. Vous bénéficiez ainsi d'un diagnostic gratuit.

Jetez un œil aux frameworks d'isolement (comme Moq comme suggéré par @Allan) pour pouvoir générer ces contrefaçons rapidement pour configurer les conditions de test et les utiliser pour faire valoir.


Plus de détails sur les contrefaçons, les simulacres et les talons: stackoverflow.com/questions/346372/…
StuperUser

4

Il existe trois raisons pour lesquelles vous souhaiterez peut-être fournir une instance fictive au test unitaire:

  1. Vous voulez limiter la portée du test, afin que le test ne soit pas affecté par les bogues dans le depndee, peut-être parce qu'il n'est pas encore terminé ou n'est pas stable ou que vous ne voulez pas que des bogues dans quelqu'un d'autre affectent vos tests.
  2. La personne à charge est compliquée à installer. Par exemple, la couche d'accès aux données est souvent simulée, car la vraie nécessite la mise en place d'une base de données de test. Vous devez toujours tester la couche d'accès aux données réelles, mais vous pouvez limiter la configuration coûteuse lors du débogage d'autres choses.
  3. Pour tester que la classe dépendante réagit correctement à divers types d'erreurs, vous fournissez une version factice qui renvoie toutes sortes de mauvaises réponses. Parce que de nombreux modes de défaillance sont assez difficiles à reproduire, mais doivent encore être testés.
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.