Je discutais des tests unitaires / d'intégration avec un collègue et ce dernier a présenté un argument intéressant contre l' écriture de tests unitaires. Je suis un grand partisan des tests unitaires (principalement JUnit), mais je suis intéressé par les prises de vues des autres, car il a soulevé des points intéressants.
Pour résumer ses points:
- En cas de modifications majeures du code (nouvel ensemble de POJO, refactoring majeur d’applications, etc.), les tests unitaires ont tendance à faire l’objet d’un commentaire plutôt qu’à être retravaillés.
- Le temps est mieux dépensé sur les tests d'intégration couvrant les cas d'utilisation, ce qui rend les tests de moindre envergure moins importants / pas du tout importants.
Des pensées à ce sujet? Je suis toujours pro-unit test (car je vois constamment qu'il produit un code amélioré), bien que les tests d'intégration semblent au moins aussi précieux.
unit-testing
integration-tests
Jeff Levine
la source
la source
Réponses:
J'ai tendance à me ranger du côté de votre ami parce que trop souvent, les tests unitaires testent les mauvaises choses .
Les tests unitaires ne sont pas mauvais en soi. Mais ils testent souvent les détails de la mise en œuvre plutôt que le flux d'entrées / sorties. Vous vous retrouvez avec des tests complètement inutiles lorsque cela se produit. Ma règle personnelle est qu'un bon test unitaire vous dit que vous venez de casser quelque chose; un mauvais test unitaire vous indique simplement que vous venez de changer quelque chose.
Un exemple qui me vient à l’esprit est un test qui a été intégré à WordPress il ya quelques années. La fonctionnalité testée tournait autour de filtres qui s’appelaient, et les tests vérifiaient que les rappels seraient ensuite appelés dans le bon ordre. Mais au lieu de (a) exécuter la chaîne pour vérifier que les rappels sont appelés dans l'ordre attendu, les tests se sont concentrés sur (b) la lecture d'un état interne qui n'aurait probablement pas dû être exposé pour commencer. Changer les éléments internes et (b) devient rouge; alors que (a) ne devient rouge que si des modifications apportées aux éléments internes annulent le résultat attendu en le faisant. (b) était clairement un test inutile à mon avis.
Si vous avez une classe qui expose quelques méthodes au monde extérieur, la chose correcte à tester à mon avis sont les dernières méthodes uniquement . Si vous testez également la logique interne, vous pouvez exposer la logique interne au monde extérieur, en utilisant des méthodes de test compliquées ou en vous lançant dans une litanie de tests unitaires qui se cassent invariablement lorsque vous souhaitez modifier quoi que ce soit.
Cela dit, je serais surpris que votre ami soit aussi critique à propos des tests unitaires que ce que vous semblez suggérer. Je pense plutôt qu'il est pragmatique. C'est-à-dire qu'il a observé que les tests unitaires écrits sont généralement inutiles. Citant: "les tests unitaires ont tendance à être commentés plutôt que retravaillés". Pour moi, il y a un message implicite là-dedans - s'ils ont tendance à avoir besoin de retravailler, c'est parce qu'ils ont tendance à être nul. En supposant que tel soit le cas, la deuxième proposition est la suivante: les développeurs perdraient moins de temps à écrire du code plus difficile à interpréter, à savoir des tests d’intégration.
En tant que tel, il ne s'agit pas d'un être meilleur ou pire. C'est juste qu'il est beaucoup plus facile de se tromper, et même très souvent mal en pratique.
la source
Avec un groupe de codeurs cow-boys indisciplinés qui pensent que tous les tests deviennent "verts" est rempli lorsque vous commentez tous les tests existants: bien sûr. Le remaniement des tests unitaires requiert la même discipline que la rédaction de première main. Vous devez donc travailler ici pour définir la "définition du fait" de votre équipe.
Ce n'est ni complètement faux ni complètement vrai. L’effort nécessaire pour rédiger des tests d’intégration utiles dépend beaucoup du type de logiciel que vous écrivez. Si vous avez un logiciel dans lequel les tests d'intégration peuvent être écrits aussi facilement que les tests unitaires, ils fonctionnent encore rapidement et vous offrent une bonne couverture de votre code, alors votre collègue marque un point. Mais pour de nombreux systèmes, j'ai constaté que ces trois points ne peuvent pas être facilement satisfaits par les tests d'intégration, c'est pourquoi vous devez vous efforcer de disposer également de tests unitaires.
la source
Je ne sais pas si j'accepte les arguments de votre collègue.
Il existe d'autres arguments plus convaincants contre les tests unitaires. Eh bien, pas exactement contre eux. Commencez par les dommages de conception induits par le test DHD . C'est un écrivain amusant, alors lis-le. Ce que j'en ai tiré:
Si vous apportez des modifications importantes à la conception de vos tests unitaires, elles peuvent entraver la réalisation d'autres objectifs de votre projet. Si possible, demandez à une personne impartiale quelle approche est la plus facile à suivre. Si votre code hautement testable est difficile à comprendre, vous risquez de perdre tous les avantages que vous avez obtenus avec le test unitaire. La surcharge cognitive liée à une trop grande abstraction vous ralentit et facilite les erreurs de fuite. Ne le négligez pas.
Si vous voulez être nuancé et philosophique, il existe de nombreuses ressources:
la source
Ne fais pas ça. Si vous trouvez quelqu'un qui fait cela, tuez-le et veillez à ce qu'il ne se reproduise pas, car leurs enfants pourraient hériter de ce gène défectueux. Si je regarde les émissions de télévision de CSI, la clé est de disperser partout des échantillons d’ADN trompeurs. De cette façon, vous polluez la scène du crime avec tant de bruit que, vu la nature coûteuse et longue des tests ADN, la probabilité qu'ils vous le détectent est astronomique.
la source
À ce stade, le processus de révision de code indique "corrige les tests unitaires" et le problème ne se pose plus :-) Si votre processus de révision de code ne détecte pas ce type de faille majeure dans le code soumis, c'est le problème.
la source
J'essaie toujours de garder le refactoring et le changement de fonctionnalité séparés. Lorsque j'ai besoin de faire les deux, je commets généralement le refactoring en premier.
Lors du refactoring de code sans changer de fonctionnalité, les tests unitaires existants sont supposés aider à garantir que le refactoring ne rompt pas accidentellement la fonctionnalité. Donc, pour un tel commit, je considérerais que la désactivation ou la suppression des tests unitaires est un signe d’avertissement majeur. Tous les développeurs qui le font devraient être avisés de ne pas le faire lors de la révision du code.
Il est possible que des modifications qui ne modifient pas les fonctionnalités entraînent toujours l'échec des tests unitaires en raison de tests unitaires erronés. Si vous comprenez le code que vous modifiez, la cause de ces échecs de tests unitaires est généralement évidente et facile à corriger.
Par exemple, si une fonction prend trois arguments, un test unitaire couvrant l'interaction entre les deux premiers arguments de la fonction n'aurait peut-être pas pris soin de fournir une valeur valide pour le troisième argument. Cette faille dans le test unitaire peut être révélée par une refactorisation du code testé, mais elle est facile à corriger si vous comprenez ce que le code est censé faire et ce que le test unitaire teste.
Lors du changement de fonctionnalités existantes, il sera généralement nécessaire de modifier également certains tests unitaires. Dans ce cas, les tests unitaires permettent de s’assurer que votre code modifie la fonctionnalité comme prévu et n’a pas d’effets secondaires indésirables.
Lorsque vous corrigez des bogues ou ajoutez de nouvelles fonctionnalités, vous devez généralement ajouter plusieurs tests unitaires. Pour ceux-ci, il peut être utile de valider d’abord les tests unitaires, puis le correctif ou la nouvelle fonctionnalité plus tard. Cela permet de vérifier plus facilement que les nouveaux tests unitaires n’ont pas réussi avec l’ancien code, mais qu’ils ont réussi avec le nouveau code. Cette approche n’est cependant pas entièrement dépourvue d’inconvénients, de sorte qu’il existe également des arguments en faveur de la validation simultanée de nouveaux tests unitaires et de mises à jour du code.
Il y a un élément de vérité à cela. Si vous pouvez obtenir une couverture des couches inférieures de la pile de logiciels avec des tests ciblant les couches les plus hautes de la pile de logiciels, vos tests peuvent être plus utiles lors du refactoring de code.
Je ne pense pas que vous trouverez un accord sur la distinction exacte entre un test unitaire et un test d'intégration. Et je ne m'inquiéterais pas si vous aviez un scénario de test dans lequel un développeur appelle un test unitaire et un autre, un test d'intégration, dans la mesure où ils peuvent convenir qu'il s'agit d'un scénario de test utile.
la source
Des tests d'intégration sont effectués pour vérifier si le système se comporte comme prévu, ce qui a toujours une valeur métier. Les tests unitaires ne font pas toujours cela. Les tests unitaires pourraient être des tests de code mort, par exemple.
Selon une philosophie de test, tout test qui ne vous fournit pas d'informations est un gaspillage. Lorsqu'un élément de code n'est pas en cours d'élaboration, ses tests unitaires sont toujours (ou presque) verts, ce qui vous donne peu ou pas d'informations.
Chaque méthode de test sera incomplète. Même si vous bénéficiez d'une couverture à 100% avec certaines métriques, vous ne passez toujours pas par presque tous les ensembles de données d'entrée possibles. Alors, ne pensez pas que les tests unitaires sont magiques.
J'ai souvent vu l'affirmation selon laquelle les tests unitaires améliorent votre code. À mon avis, les améliorations apportées par les tests unitaires au code consistent à forcer les personnes qui n'y sont pas habituées à diviser leur code en petits morceaux bien factorisés. Si vous avez l'habitude de concevoir votre code en petites parties bien pondérées, vous constaterez peut-être que vous n'avez plus besoin de tests unitaires pour vous forcer à le faire.
En fonction du nombre de tests unitaires et de la taille de votre programme, vous pouvez vous retrouver avec une quantité énorme de tests unitaires. Si c'est le cas, les gros changements deviennent plus difficiles. Si un grand changement entraîne de nombreux tests unitaires échoués, vous pouvez refuser d'effectuer le changement, effectuer beaucoup de travail pour corriger de nombreux tests ou rejeter les tests. Aucun des choix n'est idéal.
Les tests unitaires sont un outil de la boîte à outils. Ils sont là pour vous servir, pas l'inverse. Assurez-vous d'en sortir au moins autant que vous en avez mis.
la source
Les tests unitaires ne sont certainement pas la solution miracle que certains promoteurs prétendent être. Mais en général, leur rapport coûts / avantages est très positif. Ils ne rendront pas votre code "meilleur", peut-être plus modulaire. "mieux" a tellement plus de facteurs que ce que "testabilité" implique. Mais ils veilleront à ce que cela fonctionne dans tous les cas et usages auxquels vous avez pensé et éliminera la plupart de vos bogues (probablement les plus triviaux).
Le principal avantage des tests unitaires est qu'ils rendent votre code plus flexible et résilient au changement. Vous pouvez refactoriser ou ajouter des fonctionnalités et être assez confiant de ne rien casser. Cela seul les rend rentables pour la plupart des projets.
En référence aux points soulevés par votre ami:
Si l'ajout de POJO casse vos tests unitaires, ils sont probablement très mal écrits. Les POJO sont généralement la langue que vous utilisez pour parler de votre domaine. Les problèmes que vous résolvez, leur modification signifie évidemment toute votre logique métier et le code de présentation doit probablement changer. Vous ne pouvez pas vous attendre à ce que ce qui assure que ces parties de votre programme ne changent pas ...
Se plaindre que les tests unitaires sont mauvais, parce que les gens les commentent, c'est comme se plaindre d'une ceinture de sécurité, parce que les gens ne les portent pas. Si quelqu'un commente un code de test et casse quelque chose, il devrait se retrouver dans une conversation très sérieuse et désagréable avec son patron ...
Les tests d'intégration sont de loin supérieurs aux tests unitaires. pas de question. surtout si vous testez un produit. Mais écrire de bons tests d'intégration complets, qui vous donneront la même valeur, la même couverture et la même exactitude que les tests unitaires, est incroyablement difficile.
la source
Je ne peux penser qu'à un seul argument contre les tests unitaires, et il est assez faible.
Les tests unitaires montrent la majorité de leur valeur lorsque vous modifiez ou modifiez le code ultérieurement. Vous constatez une réduction considérable du temps requis pour ajouter des fonctionnalités et vous assurer que vous n'avez rien cassé.
Cependant: Il y a un coût (petit) en temps d'écriture des tests en premier lieu cependant.
Par conséquent: si un projet est suffisamment court et ne nécessite pas de maintenance / mises à jour régulières, il est possible que le coût de la rédaction des tests soit supérieur à leurs avantages.
la source