J’ai lu beaucoup de discussions sur les joies et les points impressionnants des tests unitaires. Ma question est la suivante: est-ce que quelqu’un a un bon argument contre les tests unitaires?
Il est important de comprendre que ce n’est pas gratuit. Les tests nécessitent des efforts pour écrire – et, plus important encore, pour maintenir.
Les chefs de projet et les équipes de développement doivent en être conscients.
Pratiquement aucun de mes bugs n’aurait été détecté par les tests unitaires. Mes bogues sont principalement des bogues d’intégration ou de cas d’utilisation inattendus, qui, pour les avoir trouvés plus tôt, auraient été les meilleurs tests pour des tests plus complets (et idéalement automatisés).
J’attends d’autres arguments fondés sur des preuves et moins fondés sur la religion pour les tests unitaires, comme l’a dit Dummymo. Et je ne parle pas d’une certaine expérience dans un contexte académique; Je veux dire un argument selon lequel, pour mon scénario de développement et ma capacité de programmation, les coûts-avantages seraient positifs.
Donc, être d’accord avec d’autres réponses à l’OP: parce qu’ils coûtent du temps et des coûts-bénéfices n’est pas montré.
Vous disposez d’une couche d’access aux données qui n’est pas facile à adapter au moquer.
La simple vérité est que lorsque vous écrivez du code, vous devez vous assurer qu’il fonctionne avant de dire que c’est fait. Ce qui signifie que vous l’exercez – construisez un échafaudage pour appeler la fonction, en passant des arguments, en vérifiant qu’il renvoie ce que vous attendez. Est-ce que c’est beaucoup de travail supplémentaire pour garder l’échafaudage autour de vous afin de pouvoir relancer les tests?
Eh bien oui, en fait, ça peut être. Le plus souvent, les tests échouent, même lorsque le code est correct, car les données que vous utilisiez ne sont plus cohérentes, etc.
Mais si vous avez un cadre de test unitaire en place, le coût de maintien du code de test ne peut être que marginalement plus important que le jeter. Et bien que oui, vous constaterez que beaucoup de vos cas de test échoueront à cause de problèmes avec les données que vous utilisez, au lieu de problèmes avec le code, cela se produira moins lorsque vous apprendrez à structurer vos tests pour minimiser problème.
Certes, le fait de passer vos tests unitaires ne garantit pas que votre système fonctionne. Mais cela donne une certaine garantie que certains sous-systèmes fonctionnent, ce qui n’est pas rien. Et les cas de test fournissent des exemples utiles de la manière dont les fonctions devaient être appelées.
Ce n’est pas une panacée, mais c’est une pratique utile.
Vérification formelle
Si vous pouvez prouver formellement l’exactitude du code, il n’y a aucune raison de le tester à moins que la condition du test n’apporte de nouvelles variables, auquel cas vous ne disposerez que d’une petite quantité de tests unitaires (ou de preuves pour les nouvelles variables). ).
Les tests unitaires vous indiqueront si une méthode de classe spécifique définit correctement une variable (ou une variante). Cela ne signifie en aucune façon que votre application se comportera correctement ou qu’elle gérera les circonstances qu’elle devra gérer.
Tout problème que vous pouvez penser à écrire pour un test, vous allez le gérer dans votre code, et ce problème ne va jamais apparaître. Donc, vous avez 300 tests réussis mais des scénarios réels que vous ne pensiez pas tester. L’effort requirejs pour créer et maintenir les tests ne vaut donc pas forcément la peine.
Résultats non déterministes.
Dans des cas simples, vous pouvez ensemencer le ou les générateurs aléatoires (ou les simuler) pour obtenir des résultats reproductibles, mais lorsque l’algorithme est complexe, cela devient impossible car les modifications du code modifient la demande de nombres aléatoires et modifient les résultats.
Cela se produirait rarement dans une situation commerciale, mais c’est tout à fait possible dans les jeux.
C’est l’parsing coûts / avantages habituelle.
Coût: vous devez consacrer du temps au développement et à la maintenance des tests, et affecter des ressources à leur exécution.
Les avantages sont bien connus (maintenance et refactorisation généralement moins chères avec moins de bogues).
Donc, vous équilibrez les uns dans les autres dans le cadre du projet.
Si vous savez que ce piratage rapide ne sera jamais réutilisé, les tests unitaires pourraient ne pas avoir de sens. Bien que pour être honnête, si j’avais un dollar pour chaque piratage rapide que j’avais vu courir des années plus tard ou pire, je devais continuer / refactoriser des années plus tard, je serais probablement un des investisseurs en capital-risque investis dans SO 🙂
Paresse, parfois je suis paresseux et je ne veux pas le faire!
mais sérieusement les tests unitaires sont géniaux, mais si je ne fais que coder pour mon propre plaisir, je ne le fais généralement pas parce que les projets sont de courte durée, ils sont les seuls à y travailler et ils ne sont pas si grands.
Cela peut décourager l’expérimentation de plusieurs variantes, en particulier dans les premières phases d’un projet. (Mais cela peut aussi encourager l’expérimentation dans les étapes ultérieures!)
Il ne peut pas remplacer le test du système, car il ne couvre pas la relation entre les composants. Donc, si vous devez diviser le temps de test disponible entre les tests système et les tests unitaires, alors trop de tests unitaires peuvent avoir un impact négatif sur la quantité de tests système.
Je veux append que j’encourage généralement les tests unitaires!
En résumé,
Il est impossible de généraliser là où les tests unitaires vont fournir des coûts-avantages et où ils ne le sont pas. Je vois beaucoup de gens se disputer fortement en faveur des tests unitaires et de blâmer les personnes qui ne le font pas pour ne pas utiliser suffisamment de TDD, tout en ignorant complètement le fait que les applications peuvent différer autant que le monde réel.
Par exemple, il est extrêmement difficile d’obtenir des tests à l’extérieur lorsque vous avez beaucoup de points d’intégration, soit entre les systèmes, soit entre les processus et les threads de votre propre application.
Si tout ce que vous avez fait, ce sont des sites comme Stackoverflow, où le problème est bien compris et la plupart des solutions assez sortingviales, alors oui, écrire des tests unitaires présente de nombreux avantages, mais il y a beaucoup d’applications unité testé correctement, car ils manquent, bien, “unités”.
Je ne dirais pas que c’est un argument contre, mais pour nous, nous avons une application héritée avec une TON de code et écrite en COBOL. Il est pratiquement impossible à ce stade de dire que nous voulons mettre en œuvre des tests unitaires et le faire avec un degré de précision quelconque ou dans un délai raisonnable pour les affaires, comme l’a souligné Duffymo.
Donc, je suppose que pour append à cela, peut-être un argument serait l’incapacité (dans certains cas) d’essayer de mettre en œuvre des tests unitaires une fois le développement terminé (et maintenu pendant des années).
Il n’y a jamais de raison de ne jamais écrire de tests unitaires.
Il y a de bonnes raisons de ne pas écrire de tests unitaires spécifiques. (Surtout si vous utilisez la génération de code. Vous pouvez bien sûr générer du code pour générer les tests unitaires afin de s’assurer que personne n’a caché le code généré. Mais cela dépend de la confiance de l’équipe.)
*Modifier
Oh. Et de ce que je comprends, certaines choses dans la functional programming comstacknt donc fonctionnent ou ne comstacknt pas.
Ces choses auraient-elles besoin de tests unitaires?
Je suis d’accord avec l’idée qu’il n’y a pas de bons arguments contre les tests unitaires en général . Il existe toutefois des situations spécifiques où les tests unitaires peuvent ne pas être une option viable ou du moins problématiques et / ou une proposition de retour sur investissement difficile pour le niveau d’effort requirejs pour créer et maintenir des tests.
Voici quelques exemples:
Comportement dépendant du temps réel en réponse à des conditions externes. Certains puristes peuvent prétendre qu’il ne s’agit pas de tests unitaires mais plutôt de scénarios au niveau de l’intégration ou du test du système. Cependant, j’ai écrit du code pour des fonctionnalités simples et de bas niveau pour des applications quasi incorporées où il serait utile de tester au moins partiellement la réponse en temps réel via un framework de test unitaire à des fins de test de construction / régression.
Test des fonctionnalités comportementales et / ou de niveau politique nécessitant une description de données complexe de l’état environnemental auquel le module de code testé répond. Ceci est lié au commentaire d’une affiche antérieure concernant la difficulté d’effectuer des tests unitaires impliquant une couche d’access aux données qui n’est pas facilement adaptée à la simulation. Bien que le comportement / la politique testé puisse être relativement simple, il doit être testé dans une description d’état complexe. La valeur des tests unitaires est de garantir que les conditions clés rares sont gérées correctement pour une application critique. On veut se moquer de ce dernier et créer un environnement / état simulé, mais le coût peut être élevé.
Il existe au moins deux alternatives aux tests unitaires pour les scénarios ci-dessus:
Pour les tests de fonctionnalité en temps réel ou en quasi-temps réel, des tests système approfondis peuvent être effectués pour tenter de compenser le manque de tests unitaires de qualité. Pour certaines applications, cela peut être la seule option, par exemple, des systèmes intégrés impliquant du matériel et / ou des systèmes physiques.
Créez un harnais de test ou un simulateur au niveau du système qui facilite les tests approfondis sur toute une gamme de conditions simulées de manière aléatoire. Cela peut être utile pour tester les scénarios de stratégie / comportement décrits précédemment impliquant un état environnemental complexe. Bien qu’un travail important puisse être impliqué dans la création du harnais ou du simulateur de test, le retour sur investissement peut représenter un bien meilleur rapport qualité / prix que pour les tests unitaires isolés, car une gamme beaucoup plus large de conditions peut être testée.
Étant donné que l’environnement de test implique des conditions aléatoires plutôt que spécifiques, cette approche peut ne pas offrir le niveau d’assurance souhaité pour certains scénarios critiques. Effectuer des tests approfondis peut aider à compenser cela. Alternativement, la création d’un harnais de test ou d’un simulateur de système pour des conditions aléatoires peut également aider à réduire le coût global du test de scénarios d’états complexes spécifiques, car les coûts de développement sont désormais partagés avec une gamme plus large de tests.
En fin de compte, la meilleure façon de tester les applications est de comparer les coûts aux valeurs. Le test unitaire est l’une des meilleures options et devrait toujours être utilisé dans la mesure du possible, mais il n’est pas universellement applicable à tous les scénarios. Comme beaucoup de choses dans les logiciels, il faudra parfois faire appel à un jugement et être prêt à apporter des ajustements en fonction des résultats.
Les tests unitaires sont un compromis. Je vois deux problèmes:
Ça prend du temps. Non seulement pour écrire les tests, mais aussi (et c’est le plus ennuyeux) si vous voulez effectuer un changement important, vous avez maintenant deux endroits à modifier. Dans le pire des cas, cela pourrait vous décourager de ré-architecturer votre base de code.
Il ne protège que contre les problèmes que vous pensez susceptibles de survenir et vous ne pouvez généralement pas tester les effets secondaires. Cela peut conduire à un faux sentiment de sécurité, comme mentionné précédemment.
Je conviens que les tests unitaires constituent un outil précieux pour accroître la fiabilité des logiciels d’entreprise avec une base de code relativement stable. Mais pour les projets personnels ou les projets de bébé, je pense qu’une utilisation généreuse des assertions dans votre code est un meilleur compromis.
Au lieu de les supprimer complètement, nous écrivons des tests unitaires uniquement pour les fonctionnalités essentielles telles que l’autorisation de paiement, l’authentification des utilisateurs, etc. Il est très utile d’avoir toujours des points sensibles aux modifications du code. base et vous voudriez un moyen de vérifier que ces points de contact fonctionnent sans échec dans l’AQ.
Pour écrire des tests unitaires en général, l’apprentissage de la courbe est la plus grande raison pour laquelle je sais ne pas déranger. J’essaie d’apprendre de bons tests unitaires depuis environ un an et demi, et j’ai l’impression de réussir (écrire des espions de journal d’audit, se moquer, tester 1 contrainte par test, etc.), même si je pense que accéléré le développement pour moi pendant environ un an de ce temps. Alors appelez ça 6 mois de lutte pour que ça commence à porter ses fruits. (Je faisais encore du “vrai” travail pendant cette période, bien sûr.)
La majeure partie de la douleur ressentie pendant cette période était due à l’incapacité de suivre les directives des tests de bonne unité.
Pour une variété de cas spécifiques, la capacité à tester l’unité peut être bloquée; d’autres ont commenté certains d’entre eux.
Dans le cadre du développement piloté par les tests, les tests unitaires sont en fait un moyen plus important de concevoir votre code pour qu’il soit testable. En fin de compte, votre code a tendance à être plus modulaire et l’écriture des tests permet d’étoffer les API, etc.
Cependant, trop souvent, vous développez le code, puis écrivez les tests, en commentant le code que vous venez d’écrire pour vous assurer que les tests échouent, puis en supprimant sélectivement les jetons de commentaire pour que les tests réussissent. Pourquoi? Bien, car il est beaucoup plus difficile d’écrire des tests que d’écrire du code dans certains cas. Il est également souvent beaucoup plus difficile d’écrire du code qui peut être testé de manière complètement automatisée. Pensez aux interfaces utilisateur, au code qui génère des images ou au format PDF, aux transactions de firebase database.
Les tests unitaires aident beaucoup, mais attendez-vous à écrire environ 3 fois plus de code pour les tests que vous n’écrirez pour le code actuel. De plus, tout cela devra être maintenu. Les modifications importantes apscopes à l’application invalideront d’énormes morceaux de tests – une bonne mesure de l’impact sur le système, mais quand même… Êtes-vous prêt à cela? Etes-vous dans une petite équipe où vous faites le travail de 5 développeurs? Si tel est le cas, le développement automatisé de TDD ne pourra tout simplement pas voler – vous n’aurez pas le temps de faire les choses assez rapidement. Donc, vous finissez par vous fier à vos propres tests manuels, à vos tests de qualité et au fait que vous ne faites que survivre avec des bogues, puis que vous corrigez le plus vite possible. C’est malheureux, très contraignant et exaspérant, mais c’est la réalité dans les petites entresockets qui n’embauchent pas suffisamment de développeurs pour le travail à accomplir.
Non, vraiment pas. D’après mon expérience, les gens qui présentent un argument de paille ou qui ne savent pas comment unifier les tests ne sont pas évidents.
@Khorkak – Si vous modifiez une fonctionnalité de votre code de production, seule une partie de vos tests unitaires devrait être affectée. Si vous ne le faites pas, cela signifie que vous ne découplez pas votre code de production et vos tests de manière isolée, mais plutôt que vous intégrez de gros morceaux de votre code de production. Ce ne sont que des compétences médiocres en matière de tests unitaires, et oui, c’est un gros problème. Non seulement parce que votre base de code de test d’unité deviendra difficile à gérer, mais aussi parce que votre base de code de production sera mauvaise et aura le même problème.
Les tests unitaires n’ont aucun sens pour le code jetable: Si le code est une preuve de concept Q & D, quelque chose créé pendant une pointe pour étudier différentes approches ou tout ce que vous êtes sûr est presque toujours éliminé. beaucoup de retour sur l’investissement. En fait, ils pourraient vous faire du mal car le temps passé à passer du temps à ne pas essayer une approche différente, etc. (coût alternatif)
La clé est d’être sûr que c’est le cas ou d’avoir une compréhension suffisante de la part de ses coéquipiers, etc. Si quelqu’un dit «c’est génial, utilisez-le», vous investissez alors le temps de mettre le code en conformité avec le code NON jetable.
Pour ceux qui ont demandé une meilleure preuve, je vous renvoie à cette page. http://biblio.gdinwiddie.com/biblio/StudiesOfTestDrivenDevelopment note que beaucoup d’entre elles sont des études de type académique, mais réalisées contre des groupes qui font du vrai logiciel de production, alors personnellement, il semble y avoir une assez bonne validité.