12
votes

Est-ce que je fais quelque chose de fondamentalement faux dans mes tests unitaires?

Après avoir lu un article intéressant sur le comportement des tests unitaires au lieu de l'État, je suis venu à comprendre que mes tests de l'unité sont souvent étroitement couplés à mon code parce que j'utilise des moqueurs. Je ne peux pas enregistrer des tests de l'unité sans se moquer, mais le fait est que ces maquillages accumulent beaucoup mon test de l'unité à mon code en raison de l'attente d'appels Andreturn.

Par exemple, lorsque je crée un test qui utilise une simule, j'enregistre tous les appels vers la simulation spécifique et attribuer des valeurs de retour. Maintenant, lorsque je modifie la mise en œuvre du code réel pour une raison quelconque, de nombreux tests se cassent parce que cet appel n'a pas été attendu par la simulation, ce qui vous oblige à mettre à jour le test de l'unité également et à me forcer efficacement à mettre en œuvre chaque fois que vous changez deux fois ... Cela arrive beaucoup.

Est-ce que ce problème est intrinsèque d'utiliser des simulacres et devrais-je apprendre à vivre avec elle ou je fais quelque chose de fondamentalement faux? S'il vous plaît éclairer moi :) Des exemples clairs à venir avec l'explication sont les bienvenus bien sûr.


1 commentaires

Vous devriez définitivement Google "Fowler classique Fowler", réserver une journée ou deux et lire :). IMHO, les deux ont leurs mérites et les deux devraient être utilisés lorsque la situation l'appelle.


4 Réponses :


3
votes

Si vous corrigez les tests car ils se cassent, vous ne les utilisez pas comme prévu.

Si le comportement d'une méthode change, dans le développement axé sur le test, vous modifiez d'abord le test pour attendre le nouveau comportement, puis mettez en œuvre le nouveau comportement.


2 commentaires

C'est correct et une définition très concise de TDD, mais cela ne change pas le fait que vous devez toujours mettre en œuvre des modifications deux fois, d'abord dans le test, le voir échouer, puis dans le code, voir cela réussir. Est-ce que cela «toujours implémenter deux fois le problème» intrinsèque à TDD?


@ NKR1PT: Oui, mais ce n'est pas isolé à TDD. Vous auriez plus ou moins le même problème dans tout modèle de développement qui intègre des tests sous quelque forme que ce soit. C'est juste que c'est tellement évident dans TDD.



4
votes

Mon expérience consiste à utiliser des simulacres uniquement aux bornies des systèmes (sous). Si j'ai deux classes qui sont fortement liées, je ne vous moque pas d'appart, mais les tester ensemble. Un exemple pourrait être un composite et un visiteur. Si je teste un visiteur concret, je n'utilise pas de maquette pour le composite mais crée de vrais composites. On pourrait affirmer que ce n'est pas un test unitaire (dépend de la définition de ce qui est une unité). Mais cela n'a pas d'importance. Ce que j'essaie d'atteindre est:

  1. Écrivez des tests lisibles (les tests sans moqueurs sont la plupart du temps plus facile à lire).
  2. Testez seulement une zone de code ciblée (dans l'exemple du visiteur de béton et la partie pertinente du composite).
  3. Écrivez des tests rapides (tant que j'instécresse quelques classes, dans l'exemple des composites concrets, ce n'est pas une préoccupation ... Montre pour des créations transitives).

    Seulement si je rencontre la limite d'un sous-système, j'utilise des simulacres. Exemple: J'ai un composite qui peut se rendre à un rendu, je me moquerais du rendu si je teste la logique de rendu du composite.

    Le comportement des tests au lieu de l'état ressemble au début, mais en général, je vais tester l'état à mesure que les tests résultants sont Easeear pour entretenir. Mocks sont un canon. Ne craque pas une noix avec un slgedyhammer.


4 commentaires

Bien que je suis d'accord avec le sens de cela, beaucoup de systèmes sont suffisamment peu profonds dans des endroits suffisamment peu profonds qu'il y a très peu de différence entre se moquer de tout le temps et se moquer uniquement des limites du sous-système.


Dans ce cas: Donnez à la profondeur les systèmes. Déposez clairement les sous-systèmes!


Si vous vous sentez bien tester un certain nombre de classes dans une unité, l'étape suivante est peut-être pour consolider cette unité en une seule classe.


Peut-être que ... mais peut-être pour emballer toutes les fonctionnalités en une seule classe rend la classe à faire beaucoup.



5
votes

Quand je crée un test qui utilise un simulateur, J'enregistre tous les appels vers le spécifique Mock et attribuer des valeurs de retour

On dirait que vous êtes peut-être sur-spécifiant les attentes.

Essayez de construire comme peu de code de configuration que possible dans vos tests: Stub (plutôt que d'attendre) Tous les comportements qui ne concernent pas le test actuel et spécifient uniquement les valeurs de retour qui sont absolument nécessaires pour effectuer votre travail de test.

Cette réponse comprend un exemple concis ( ainsi qu'une alternative, une explication plus détaillée).


0 commentaires

0
votes

Plusieurs bonnes réponses ici déjà, mais pour moi une bonne règle, c'est de tester les exigences de la méthode, pas de la mise en œuvre. Parfois, cela peut signifier d'utiliser un objet simulé car l'interaction est l'exigence, mais vous préférez généralement tester la valeur de retour de la méthode ou la modification de l'état de l'objet.


0 commentaires