Ai-je besoin d'un test unitaire si j'ai déjà un test d'intégration?

47

Si j’ai déjà un test d’intégration pour mon programme et que tous ont réussi, j’ai le sentiment que cela fonctionnera. Alors quelles sont les raisons pour écrire / ajouter des tests unitaires? De toute façon, comme je dois déjà écrire des tests d'intégration, j'aimerai écrire uniquement des tests unitaires pour les parties non couvertes par les tests d'intégration.

Ce que je sais des avantages des tests unitaires par rapport aux tests d'intégration

  • Petit et donc rapide à exécuter (mais ajouter une nouvelle unité pour tester quelque chose a déjà été testé avec un test d'intégration signifie que ma combinaison de test devient plus grande et plus longue à fonctionner)
  • Localisez le bogue plus facilement car il ne teste qu'une chose (mais je peux démarrer le test unitaire d'écriture pour vérifier chaque pièce individuellement lorsque mon test d'intégration a échoué)
  • Trouvez un bug qui peut ne pas être pris dans le test d'intégration. par exemple masquer / compenser les bugs. (Mais si tous les tests d'intégration réussissent, ce qui signifie que mon programme fonctionnera même s'il existe un bogue caché. Donc, trouver / corriger ces bogues ne sont pas vraiment une priorité élevée, à moins qu'ils ne cassent les futurs tests d'intégration ou ne causent pas de problèmes de performances)

Et nous voulons toujours écrire moins de code, mais écrire des tests unitaires nécessite beaucoup plus de code (principalement des objets fictifs). La différence entre certains de mes tests unitaires et mes tests d'intégration réside dans le fait que, dans les tests unitaires, j'utilise un objet factice et dans les tests d'intégration, j'utilise un objet réel. Qui ont beaucoup de duplication et je n'aime pas le code dupliqué, même dans les tests car cela ajoute une surcharge pour changer le comportement du code (l'outil de refactorisation ne peut pas tout faire tout le temps).

Bryan Chen
la source
Par curiosité, quelle est la couverture de vos tests d’intégration? En outre, si votre logique est complexe, vos tests d'intégration les couvrent-ils entièrement ou en partie, et quelles parties, importantes pour l'entreprise ou aléatoires?
civan
Cette question semble ambiguë. Disons que j'ai une méthode de contrôleur Rails qui appelle un interacteur ( github.com/collectiveidea/interactor ). J'ai décidé d'écrire des tests d'intégration pour ma méthode de contrôleur (car sans eux, je ne peux pas croire que mon noeud final d'API fonctionne). Il y a au moins deux questions ici: (1) devrais-je également écrire des tests unitaires pour mes méthodes de contrôleur (par exemple, devrais-je écrire des tests unitaires qui testent le même comportement que mes tests d'intégration), et (2) devrais-je également écrire des tests unitaires pour mon interacteur? Je répondrais différemment à ces deux questions dans certains contextes professionnels.
Daniel

Réponses:

33

Vous avez présenté de bons arguments pour et contre les tests unitaires. Donc , vous devez vous demander, « Suis-je vois la valeur dans les arguments positifs qui l' emportent sur les coûts dans les négatifs de? » Je fais certainement:

  • Small-and-fast est un bel aspect des tests unitaires, bien qu'il ne soit en aucun cas le plus important.
  • Locating-bug [s] -easier est extrêmement précieux. De nombreuses études sur le développement de logiciels professionnels ont montré que le coût d'un bogue augmente considérablement avec son vieillissement et son chemin dans la chaîne de fourniture de logiciels.
  • La recherche de bugs masqués est précieuse. Lorsque vous savez que tous les comportements d’un composant particulier sont vérifiés, vous pouvez l’utiliser d’une manière qu’il n’avait pas utilisée auparavant, en toute confiance. Si la seule vérification consiste à effectuer des tests d'intégration, vous savez uniquement que ses utilisations actuelles se comportent correctement.
  • Se moquer est coûteux dans les cas réels, et le maintien des simulacres l'est encore plus. En fait, lorsque vous vous moquez d'objets ou d'interfaces "intéressants", vous pouvez même avoir besoin de tests qui vérifient que vos objets fictifs modélisent correctement vos objets réels!

Dans mon livre, les avantages l'emportent sur les inconvénients.

Ross Patterson
la source
2
Est-ce que se moquer moins cher dans des cas réels? Vous ne faites qu'attendre des attentes quant aux messages reçus par la maquette et spécifier ce qu'elle retournera.
Dogweather
10
@Dogweather Mocks fonctionne bien lors de sa création. À mesure que le temps passe et que l'objet réel change, les simulacres doivent changer avec lui. Après 10 ans et 6 000 tests unitaires, il est très difficile de savoir que vos tests «réussis» le sont vraiment.
Ross Patterson
1
En passant, ces "10 ans et 6 000 tests unitaires" sont des chiffres tirés de l'expérience personnelle et non de l'hyperbole.
Ross Patterson
3
J'ai commencé à écrire des tests automatisés pour les développeurs (unités et intégration, mais surtout ces dernières) en 2004 ou 2005, et j'ai développé une bibliothèque de moquage avancée pour Java. Plusieurs fois, j’ai vu plusieurs tests d’intégration se rompre pour la même raison (changement de la base de données ou réseau) et j’écris parfois des tests d’intégration "de niveau inférieur" pour des composants réutilisables, mais je préfère quand même avoir uniquement tests d'intégration. Les tests unitaires isolés avec moqueries, la plupart du temps, n'en valent simplement pas la peine; J'utilise moqueur seulement comme aide pour les tests d'intégration.
Rogério
Votre dernier point semble contredire l’argument que vous avancez. Dans ce point, vous plaidez contre l'écriture de simulacres inutiles, ce qui est un argument contre l'écriture de tests unitaires pour des pièces déjà couvertes par des tests d'intégration. Cependant, votre argument est en faveur de l’écriture de tests unitaires pour les pièces déjà couvertes par les tests d’intégration. Pourriez-vous clarifier votre intention ici @RossPatterson?
Daniel
8

Je ne vois pas l'utilité de réimplémenter un test d'intégration existant comme un tare.

Les tests d'intégration sont souvent beaucoup plus faciles à écrire pour les applications héritées non tdd car, en règle générale, les fonctionnalités à tester sont étroitement associées, ce qui permet de tester des unités isolément (= unittesting) peut être difficile, coûteux ou impossible.

> Then what are the reasons to write/add unit tests?

À mon avis, le développement piloté par les tests est plus efficace si vous écrivez les tests unitaires avant le code réel. De cette façon, le code qui remplit les tests devient clairement séparé avec un minimum de références externes facilement testable.

Si le code existe déjà sans les tests unitaires, l'écriture ultérieure des tests unitaires demande généralement beaucoup de travail supplémentaire, car le code n'a pas été écrit pour faciliter les tests.

Si vous utilisez TDD, le code est facilement testable.

k3b
la source
2
Si j’ai une application héritée qui n’a pas de numéro unit-testset que je souhaite inclure unit-testspour certaines parties, pensez-vous qu’il est préférable d’écrire d’abord le integration testscode correspondant à l’ancien. Une fois cela écrit, vous pouvez alors dissocier le couplage étroit et créer des fonctions avec des interfaces pouvant être testées? Puisque vous avez integration-testdéjà écrit, vous pouvez alors vérifier à chaque étape du refactoring, que la nouvelle version du code fonctionne toujours comme vous le souhaitez?
alpha_989
2
@ alpha_989, c'est à mon humble avis et je suis ouvert à d'autres idées, mais je préférerais les tests d'intégration aux tests unitaires pour le code hérité. Dans les deux cas, vous devez vous assurer que les méthodes fonctionnent correctement avant d'ajouter tout type de test, mais les tests d'intégration garantissent que les attentes globales des méthodes fonctionnent par opposition aux éléments de code individuels.
Britt Wescott
5

Les tests d'intégration doivent uniquement vérifier que plusieurs composants fonctionnent ensemble comme prévu. Que la logique des composants individuels soit exacte ou non doit être vérifiée par des tests unitaires.
La plupart des méthodes ont plusieurs chemins d’exécution possibles; Pensez aux variables if-then-else, aux variables d'entrée avec des valeurs inattendues ou tout simplement fausses, etc. Les développeurs ont généralement tendance à ne penser qu'à la bonne voie: la voie normale qui ne va pas mal. Mais en ce qui concerne ces autres chemins, vous avez deux options: vous pouvez laisser votre utilisateur final les explorer à travers les actions qu'il effectue dans l'interface utilisateur et espérer qu'il ne bloque pas votre application, ou vous pouvez écrire des tests unitaires affirmant le comportement de ces autres chemins et prendre des mesures si nécessaire.

Stefan Billiet
la source
4

Certaines des raisons que vous avez mentionnées dans votre question sont vraiment importantes et pourraient à elles seules faire valoir le bien-fondé des tests unitaires, mais du YMMV. Par exemple, à quelle fréquence exécutez-vous votre suite de tests intégrée? Mon expérience avec les tests intégrés est que tôt ou tard, ils deviendront si lents que vous ne les exécuterez pas à chaque fois que vous apporterez un changement et que le temps entre l'insertion et la détection d'un bogue augmentera.

En outre, une grosse erreur que vous faites peut-être est de croire que

Find bug that may not be caught in integration test. e.g. masking/offsetting bugs.

n'est pas important. Vous attendez-vous à ce que vos utilisateurs trouvent les bogues pour vous? Faire confiance aux couvertures obtenues à partir de tests intégrés est dangereux à mon avis, vous pouvez très facilement obtenir un pourcentage élevé de couverture, mais en réalité, vous testez très peu.

Je suppose que la référence canonique aux tests intégrés sont les posts de JBrains:

http://www.jbrains.ca/permalink/integrated-tests-are-a-scam-part-1

au cas où vous ne les avez pas déjà lus.

Enfin, le retour d’information que vous pouvez obtenir des tests unitaires pour votre conception est inestimable. Juger sur un design en se basant sur des tests intégrés peut également être une erreur.

José Ricardo
la source
Je ne comprends pas vraiment cet article. Donc, il y a beaucoup de chemins de code et les tests d'intégration ne peuvent pas les couvrir tous ... alors? La même chose s’applique aux tests unitaires, à moins que vos unités ne soient trop triviales pour être inutiles.
Casey
Cela ressemble plus à un argument contre la fixation de la couverture de code que de rédiger une tonne de tests unitaires et d’éviter les tests d’intégration.
Casey
1

Si vous envisagez de devoir modifier ou refactoriser votre code, il est essentiel de procéder à des tests unitaires. Les tests unitaires existent non seulement pour démontrer les bogues au moment de l'écriture du code, mais aussi pour indiquer quand de nouveaux bogues apparaissent lorsque plus de code est écrit.

Oui, il est préférable de commencer par écrire vos tests d'intégration et vos tests unitaires, mais il est très utile de les avoir même s'ils sont écrits plus tard.

Matthew Flynn
la source
3
Je ne pense pas que vous ayez plaidé la cause. Les tests d'intégration révéleraient également des bogues dans le code et seraient en fait capables de détecter des bogues que les tests unitaires ne parviendraient pas.
Casey