Je regardais les webémissions de Rob Connerys sur l'application MVCStoreFront, et j'ai remarqué qu'il testait unitaire même les choses les plus banales, des choses comme:
public Decimal DiscountPrice
{
get
{
return this.Price - this.Discount;
}
}
Aurait un test comme:
[TestMethod]
public void Test_DiscountPrice
{
Product p = new Product();
p.Price = 100;
p.Discount = 20;
Assert.IsEqual(p.DiscountPrice,80);
}
Alors que je suis tout à fait pour les tests unitaires, je me demande parfois si cette forme de premier développement de test est vraiment bénéfique, par exemple, dans un processus réel, vous avez 3-4 couches au-dessus de votre code (demande commerciale, document d'exigences, document d'architecture) , où la règle métier réelle définie (le prix de remise est le prix - la remise) peut être mal définie.
Si tel est le cas, votre test unitaire ne vous dit rien.
De plus, votre test unitaire est un autre point d'échec:
[TestMethod]
public void Test_DiscountPrice
{
Product p = new Product();
p.Price = 100;
p.Discount = 20;
Assert.IsEqual(p.DiscountPrice,90);
}
Maintenant, le test est défectueux. Évidemment, dans un simple test, ce n'est pas grave, mais disons que nous testions une règle métier compliquée. Que gagnons-nous ici?
Avance rapide de deux ans dans la vie de l'application, lorsque les développeurs de maintenance la maintiennent. Maintenant que l'entreprise change sa règle, et le test se brise à nouveau, un développeur débutant corrige alors le test de manière incorrecte ... nous avons maintenant un autre point d'échec.
Tout ce que je vois, ce sont plus de points d'échec possibles, sans réel retour bénéfique, si le prix réduit est erroné, l'équipe de test trouvera toujours le problème, comment les tests unitaires ont-ils sauvé du travail?
Qu'est-ce que j'oublie ici? S'il vous plaît, apprenez-moi à aimer TDD, car j'ai du mal à l'accepter comme utile jusqu'à présent. Je veux aussi, parce que je veux rester progressiste, mais cela n'a pas de sens pour moi.
EDIT: Quelques personnes n'arrêtent pas de mentionner que les tests aident à appliquer la spécification. D'après mon expérience, les spécifications sont également erronées, le plus souvent, mais peut-être que je suis condamné à travailler dans une organisation où les spécifications sont écrites par des personnes qui ne devraient pas écrire de spécifications.
la source
Réponses:
Premièrement, les tests sont comme la sécurité - vous ne pouvez jamais être sûr à 100% de l'avoir, mais chaque couche ajoute plus de confiance et un cadre pour résoudre plus facilement les problèmes qui subsistent.
Deuxièmement, vous pouvez diviser les tests en sous-programmes qui peuvent eux-mêmes être testés. Lorsque vous avez 20 tests similaires, créer un sous-programme (testé) signifie que votre test principal consiste en 20 appels simples du sous-programme, ce qui est beaucoup plus susceptible d'être correct.
Troisièmement, certains diront que TDD répond à cette préoccupation. Autrement dit, si vous n'écrivez que 20 tests et qu'ils réussissent, vous n'êtes pas complètement convaincu qu'ils testent réellement quoi que ce soit. Mais si chaque test que vous avez écrit initialement a échoué , puis que vous l'avez corrigé, vous êtes beaucoup plus sûr qu'il teste vraiment votre code. À mon humble avis, ce va-et-vient prend plus de temps qu'il n'en vaut la peine, mais c'est un processus qui tente de répondre à votre préoccupation.
la source
Un test erroné est peu susceptible de casser votre code de production. Du moins, pas pire que de ne pas avoir de test du tout. Ce n'est donc pas un "point d'échec": les tests n'ont pas besoin d'être corrects pour que le produit fonctionne réellement. Ils doivent peut-être être corrects avant d'être validés comme fonctionnant, mais le processus de correction des tests interrompus ne met pas en danger votre code d'implémentation.
Vous pouvez considérer les tests, même les tests triviaux comme ceux-ci, comme une seconde opinion sur ce que le code est censé faire. Une opinion est le test, l'autre est la mise en œuvre. S'ils ne sont pas d'accord, alors vous savez que vous avez un problème et vous regardez de plus près.
C'est également utile si quelqu'un souhaite à l'avenir implémenter la même interface à partir de zéro. Ils ne devraient pas avoir à lire la première implémentation pour savoir ce que signifie Discount, et les tests agissent comme une sauvegarde sans ambiguïté de toute description écrite de l'interface que vous pourriez avoir.
Cela dit, vous échangez du temps. S'il y a d'autres tests que vous pourriez écrire en utilisant le temps que vous gagnez en sautant ces tests triviaux, ils seraient peut-être plus précieux. Cela dépend vraiment de la configuration de votre test et de la nature de l'application. Si la remise est importante pour l'application, vous allez quand même attraper des bogues dans cette méthode lors des tests fonctionnels. Tous les tests unitaires n'est que vous laissez les attraper au point que vous testez cette unité, lorsque l'emplacement de l'erreur sera immédiatement évident, au lieu d'attendre jusqu'à ce que l'application est intégrée ensemble et l'emplacement de l'erreur peut être moins évidente.
Au fait, personnellement, je n'utiliserais pas 100 comme prix dans le cas de test (ou plutôt, si je le faisais, j'ajouterais un autre test avec un autre prix). La raison en est que quelqu'un à l'avenir pourrait penser que la remise est censée être un pourcentage. L'un des objectifs de tests triviaux comme celui-ci est de s'assurer que les erreurs de lecture de la spécification sont corrigées.
[Concernant l'édition: je pense qu'il est inévitable qu'une spécification incorrecte soit un point d'échec. Si vous ne savez pas ce que l'application est censée faire, il y a de fortes chances qu'elle ne le fasse pas. Mais écrire des tests pour refléter les spécifications n'amplifie pas ce problème, cela ne parvient simplement pas à le résoudre. Vous n'ajoutez donc pas de nouveaux points de défaillance, vous représentez simplement les défauts existants dans le code au lieu de la documentation de
gaufres.]la source
Les tests unitaires ne sont pas vraiment censés sauver du travail, ils sont censés vous aider à trouver et à prévenir les bogues. C'est plus de travail, mais c'est le bon type de travail. Il s'agit de réfléchir à votre code aux plus bas niveaux de granularité et d'écrire des cas de test qui prouvent qu'il fonctionne dans les conditions attendues , pour un ensemble donné d'entrées. Il isole les variables pour que vous puissiez gagner du temps en cherchant au bon endroit quand un bogue se présente. C'est enregistrer cette suite de tests afin que vous puissiez les utiliser encore et encore lorsque vous devez faire un changement plus tard.
Je pense personnellement que la plupart des méthodologies ne sont pas beaucoup d'étapes retirées de l' ingénierie logicielle culte du fret , TDD inclus, mais vous n'avez pas à adhérer à un TDD strict pour profiter des avantages des tests unitaires. Gardez les bonnes pièces et jetez celles qui ne rapportent que peu d'avantages.
Enfin, la réponse à votre question titulaire " Comment testez-vous un test unitaire? " Est que vous ne devriez pas avoir à le faire. Chaque test unitaire doit être simple et insensé. Appelez une méthode avec une entrée spécifique et comparez-la à sa sortie attendue. Si la spécification d'une méthode change, vous pouvez vous attendre à ce que certains des tests unitaires de cette méthode doivent également changer. C'est l'une des raisons pour lesquelles vous effectuez des tests unitaires à un niveau de granularité si bas, de sorte que seuls certains des tests unitaires doivent changer. Si vous constatez que les tests pour de nombreuses méthodes différentes changent pour un changement dans une exigence, il se peut que vous ne testiez pas à un niveau de granularité suffisamment fin.
la source
Les tests unitaires sont là pour que vos unités (méthodes) fassent ce que vous attendez. L'écriture du test vous oblige d'abord à réfléchir à ce que vous attendez avant d'écrire le code. Penser avant de faire est toujours une bonne idée.
Les tests unitaires doivent refléter les règles métier. Certes, il peut y avoir des erreurs dans le code, mais l'écriture du test en premier vous permet de l'écrire du point de vue de la règle métier avant qu'un code n'ait été écrit. Écrire le test après, je pense, est plus susceptible de conduire à l'erreur que vous décrivez parce que vous savez comment le code l'implémente et que vous êtes simplement tenté de vous assurer que l'implémentation est correcte - pas que l'intention est correcte.
De plus, les tests unitaires ne sont qu'une forme - et la plus basse, en plus - des tests que vous devriez écrire. Des tests d'intégration et des tests d'acceptation doivent également être rédigés, ces derniers par le client, si possible, pour s'assurer que le système fonctionne comme prévu. Si vous trouvez des erreurs lors de ce test, revenez en arrière et écrivez des tests unitaires (qui échouent) pour tester le changement de fonctionnalité pour le faire fonctionner correctement, puis modifiez votre code pour que le test réussisse. Vous avez maintenant des tests de régression qui capturent vos corrections de bogues.
[ÉDITER]
Une autre chose que j'ai trouvée avec le TDD. Cela force presque une bonne conception par défaut. Cela est dû au fait que les conceptions hautement couplées sont presque impossibles à tester isolément. Il ne faut pas beaucoup de temps avec TDD pour comprendre que l'utilisation d'interfaces, d'inversion de contrôle et d'injection de dépendances - tous les modèles qui amélioreront votre conception et réduiront le couplage - sont vraiment importantes pour le code testable.
la source
Comment tester un test ? Le test de mutation est une technique précieuse que j'ai personnellement utilisée avec un effet étonnamment bon. Lisez l'article lié pour plus de détails et des liens vers encore plus de références académiques, mais en général, il "teste vos tests" en modifiant votre code source (en remplaçant "x + = 1" par "x - = 1" par exemple), puis réexécutez vos tests, en vous assurant qu'au moins un test échoue. Toutes les mutations qui n'entraînent pas d'échecs de test sont signalées pour une enquête ultérieure.
Vous seriez surpris de voir comment vous pouvez avoir une couverture à 100% des lignes et des succursales avec un ensemble de tests qui semblent complets, et pourtant vous pouvez fondamentalement changer ou même commenter une ligne dans votre source sans qu'aucun des tests ne se plaint. Souvent, cela revient à ne pas tester avec les bonnes entrées pour couvrir tous les cas limites, parfois c'est plus subtil, mais dans tous les cas, j'ai été impressionné par tout ce qui en a résulté.
la source
Lors de l'application du développement piloté par les tests (TDD), on commence par un test qui échoue . Cette étape, qui peut sembler inutile, est en fait là pour vérifier que le test unitaire teste quelque chose. En effet, si le test n'échoue jamais, il n'apporte aucune valeur et pire, conduit à une fausse confiance car vous vous fiez à un résultat positif qui ne prouve rien.
En suivant strictement ce processus, toutes les «unités» sont protégées par le filet de sécurité des tests unitaires, même les plus banals.
Il n'y a aucune raison pour que le test évolue dans cette direction - ou je manque quelque chose dans votre raisonnement. Lorsque le prix est de 100 et la remise de 20, le prix de remise est de 80. C'est comme un invariant.
Imaginez maintenant que votre logiciel doit prendre en charge un autre type de remise en fonction du pourcentage, peut-être en fonction du volume acheté, votre méthode Product :: DiscountPrice () peut devenir plus compliquée. Et il est possible que l'introduction de ces changements enfreigne la règle de remise simple que nous avions initialement. Ensuite, vous verrez la valeur de ce test qui détectera immédiatement la régression.
Rouge - Vert - Refactoriser - c'est pour se souvenir de l'essence du processus TDD.
Le rouge fait référence à la barre rouge de JUnit lorsqu'un test échoue.
Le vert est la couleur de la barre de progression JUnit lorsque tous les tests réussissent.
Refactoriser sous condition verte: supprimez toute duplication, améliorez la lisibilité.
Maintenant, pour aborder votre point sur les «3-4 couches au-dessus du code», cela est vrai dans un processus traditionnel (en cascade), pas lorsque le processus de développement est agile. Et l'agilité est le monde d'où vient le TDD; TDD est la pierre angulaire de la programmation eXtreme .
Agile concerne la communication directe plutôt que les documents d'exigences jetés par-dessus le mur.
la source
De petits tests triviaux comme celui-ci peuvent être le "canari dans la mine de charbon" pour votre base de code, alertant du danger avant qu'il ne soit trop tard. Les tests triviaux sont utiles à garder car ils vous aident à obtenir les bonnes interactions.
Par exemple, pensez à un test trivial mis en place pour savoir comment utiliser une API que vous ne connaissez pas. Si ce test est pertinent par rapport à ce que vous faites dans le code qui utilise l'API "pour de vrai", il est utile de garder ce test à portée de main. Lorsque l'API publie une nouvelle version et que vous devez mettre à niveau. Vous avez maintenant vos hypothèses sur la façon dont vous vous attendez à ce que l'API se comporte enregistrées dans un format exécutable que vous pouvez utiliser pour intercepter les régressions.
Si vous codez depuis des années sans écrire de tests, il se peut que vous ne sachiez pas immédiatement qu'il y a une valeur. Mais si vous pensez que la meilleure façon de travailler est de «publier tôt, publier souvent» ou «agile» en ce sens que vous voulez pouvoir déployer rapidement / continuellement, alors votre test signifie définitivement quelque chose. La seule façon de le faire est de légitimer chaque modification que vous apportez au code avec un test. Quelle que soit la taille du test, une fois que vous avez une suite de tests verte, vous pouvez théoriquement déployer. Voir aussi «production continue» et «bêta perpétuelle».
Vous n'avez pas non plus besoin d'être "test premier" pour avoir cet état d'esprit, mais c'est généralement le moyen le plus efficace d'y arriver. Lorsque vous faites du TDD, vous vous enfermez dans un petit cycle Red Green Refactor de deux à trois minutes. À aucun moment, vous ne pouvez vous arrêter et partir et avoir un désordre complet sur vos mains qui prendra une heure à déboguer et à remonter.
Un test réussi est celui qui démontre une défaillance du système. Un test échoué vous alertera d'une erreur dans la logique du test ou dans la logique de votre système. Le but de vos tests est de casser votre code ou de prouver qu'un scénario fonctionne.
Si vous écrivez des tests après le code, vous courez le risque d'écrire un test qui est «mauvais» car pour voir que votre test fonctionne vraiment, vous devez le voir à la fois cassé et fonctionnel. Lorsque vous écrivez des tests après le code, cela signifie que vous devez "lancer le piège" et introduire un bogue dans le code pour voir le test échouer. La plupart des développeurs ne sont pas seulement inquiets à ce sujet, mais soutiennent que c'est une perte de temps.
Il y a certainement un avantage à faire les choses de cette façon. Michael Feathers définit le «code hérité» comme un «code non testé». Lorsque vous adoptez cette approche, vous légitimez chaque modification que vous apportez à votre base de code. C'est plus rigoureux que de ne pas utiliser de tests, mais lorsqu'il s'agit de maintenir une base de code volumineuse, cela se paie de lui-même.
En parlant de plumes, il y a deux excellentes ressources que vous devriez consulter à ce sujet:
Ces deux explications expliquent comment intégrer ces types de pratiques et de disciplines dans des projets qui ne sont pas «Greenfield». Ils fournissent des techniques pour écrire des tests autour de composants étroitement couplés, de dépendances câblées et de choses sur lesquelles vous n'avez pas nécessairement de contrôle. Il s'agit de trouver des «coutures» et de tester autour de celles-ci.
De telles habitudes sont comme un investissement. Les retours ne sont pas immédiats; ils s'accumulent avec le temps. L'alternative à ne pas tester est essentiellement de s'endetter de ne pas pouvoir détecter les régressions, d'introduire du code sans crainte d'erreurs d'intégration ou de prendre des décisions de conception. La beauté est que vous légitimisez chaque changement introduit dans votre base de code.
Je considère cela comme une responsabilité professionnelle. C'est un idéal vers lequel tendre. Mais c'est très difficile à suivre et fastidieux. Si vous vous en souciez et pensez que vous ne devriez pas produire de code qui ne soit pas testé, vous pourrez trouver la volonté d'apprendre de bonnes habitudes de test. Une chose que je fais beaucoup maintenant (comme d'autres) est de me donner une heure pour écrire du code sans aucun test du tout, puis d'avoir la discipline de le jeter. Cela peut sembler inutile, mais ce n'est pas vraiment le cas. Ce n'est pas comme si cet exercice coûtait des matériaux physiques à une entreprise. Cela m'a aidé à comprendre le problème et à écrire du code de manière à ce qu'il soit à la fois de meilleure qualité et testable.
Mon conseil serait finalement que si vous n'avez vraiment pas le désir d'être bon dans ce domaine, alors ne le faites pas du tout. De mauvais tests qui ne sont pas maintenus, qui ne fonctionnent pas bien, etc. peuvent être pires que de ne pas avoir de tests. Il est difficile d'apprendre par vous-même et vous n'aimerez probablement pas cela, mais il sera presque impossible d'apprendre si vous n'avez pas le désir de le faire ou si vous ne pouvez pas y voir suffisamment de valeur pour justifie l'investissement en temps.
Le clavier d'un développeur est l'endroit où le caoutchouc rencontre la route. Si la spécification est fausse et que vous ne lève pas le drapeau dessus, il est fort probable que vous en soyez blâmé. Ou du moins votre code le fera. La discipline et la rigueur impliquées dans les tests sont difficiles à respecter. Ce n'est pas du tout facile. Cela demande de la pratique, beaucoup d'apprentissage et beaucoup d'erreurs. Mais finalement, cela porte ses fruits. Sur un projet au rythme rapide et en évolution rapide, c'est la seule façon de dormir la nuit, peu importe si cela vous ralentit.
Une autre chose à laquelle il faut penser ici est que des techniques qui sont fondamentalement les mêmes que les tests ont fait leurs preuves dans le passé: "salle blanche" et "conception par contrat" ont toutes deux tendance à produire les mêmes types de constructions de "méta" -code que les tests le font et les appliquent à différents moments. Aucune de ces techniques n'est une solution miracle, et la rigueur va vous coûter en fin de compte la portée des fonctionnalités que vous pouvez offrir en termes de délai de mise sur le marché. Mais ce n'est pas de cela qu'il s'agit. Il s'agit de pouvoir maintenir ce que vous livrez. Et c'est très important pour la plupart des projets.
la source
Les tests unitaires fonctionnent de manière très similaire à la comptabilité en partie double. Vous énoncez la même chose (règle métier) de deux manières très différentes (en tant que règles programmées dans votre code de production et en tant qu'exemples simples et représentatifs dans vos tests). Il est très peu probable que vous fassiez la même erreur dans les deux, donc s'ils sont tous les deux d'accord, il est peu probable que vous vous trompiez.
Comment les tests vont-ils en valoir la peine? D'après mon expérience, au moins quatre façons, au moins lors du développement piloté par les tests:
la source
La plupart des tests unitaires, des hypothèses de test. Dans ce cas, le prix réduit doit être le prix moins la réduction. Si vos hypothèses sont fausses, je parie que votre code est également faux. Et si vous faites une erreur stupide, le test échouera et vous le corrigerez.
Si les règles changent, le test échouera et c'est une bonne chose. Vous devez donc également modifier le test dans ce cas.
En règle générale, si un test échoue tout de suite (et que vous n'utilisez pas le test first design), soit le test, soit le code est erroné (ou les deux si vous passez une mauvaise journée). Vous utilisez le bon sens (et éventuellement par les spécifications) pour corriger le code incriminé et relancer le test.
Comme Jason l'a dit, les tests sont la sécurité. Et oui, parfois ils introduisent du travail supplémentaire en raison de tests défectueux. Mais la plupart du temps, ils font gagner du temps. (Et vous avez l'occasion parfaite de punir le mec qui brise le test (on parle de poulet en caoutchouc)).
la source
Testez tout ce que vous pouvez. Même des erreurs insignifiantes, comme oublier de convertir des mètres en pieds peuvent avoir des effets secondaires très coûteux. Écrivez un test, écrivez le code pour le vérifier, faites-le passer, passez à autre chose. Qui sait à un moment donné dans le futur, quelqu'un peut changer le code de réduction. Un test peut détecter le problème.
la source
Je vois les tests unitaires et le code de production comme ayant une relation symbiotique. En termes simples: l'un teste l'autre. Et les deux testent le développeur.
la source
N'oubliez pas que le coût de la correction des défauts augmente (de façon exponentielle) à mesure que les défauts vivent tout au long du cycle de développement. Oui, l'équipe de test peut détecter le défaut, mais il faudra (généralement) plus de travail pour isoler et corriger le défaut à partir de ce point que si un test unitaire avait échoué, et il sera plus facile d'introduire d'autres défauts tout en le corrigeant si vous n'ont pas de tests unitaires à exécuter.
C'est généralement plus facile à voir avec quelque chose de plus qu'un exemple trivial ... et avec des exemples triviaux, eh bien, si vous gâchez le test unitaire d'une manière ou d'une autre, la personne qui l'examinera détectera l'erreur dans le test ou l'erreur dans le code, ou tous les deux. (Ils sont en cours de révision, n'est-ce pas?) Comme le souligne tvanfosson , les tests unitaires ne sont qu'une partie d'un plan SQA.
En un sens, les tests unitaires sont une assurance. Ils ne garantissent pas que vous détecterez tous les défauts, et il peut parfois sembler que vous dépensez beaucoup de ressources, mais lorsqu'ils détectent des défauts que vous pouvez réparer, vous dépenserez beaucoup moins. que si vous n'aviez aucun test et que vous deviez corriger tous les défauts en aval.
la source
Je comprends votre point de vue, mais il est clairement exagéré.
Votre argument est fondamentalement: les tests introduisent un échec. Par conséquent, les tests sont mauvais / perte de temps.
Bien que cela puisse être vrai dans certains cas, ce n'est guère la majorité.
TDD suppose: Plus de tests = Moins d'échecs.
Les tests sont plus susceptibles de détecter les points de défaillance que de les introduire.
la source
Encore plus d'automatisation peut aider ici! Oui, l'écriture de tests unitaires peut demander beaucoup de travail, alors utilisez des outils pour vous aider. Jetez un œil à quelque chose comme Pex, de Microsoft, si vous utilisez .Net. Il créera automatiquement des suites de tests unitaires pour vous en examinant votre code. Il proposera des tests offrant une bonne couverture, en essayant de couvrir tous les chemins à travers votre code.
Bien sûr, rien qu'en regardant votre code, il ne peut pas savoir ce que vous essayiez réellement de faire, donc il ne sait pas si c'est correct ou non. Mais, cela générera des cas de tests intéressants pour vous, et vous pourrez ensuite les examiner et voir s'il se comporte comme prévu.
Si vous allez ensuite plus loin et écrivez des tests unitaires paramétrés (vous pouvez vraiment les considérer comme des contrats), cela générera des cas de tests spécifiques à partir de ceux-ci, et cette fois, il pourra savoir si quelque chose ne va pas, car vos assertions dans vos tests échoueront.
la source
J'ai réfléchi un peu à une bonne manière de répondre à cette question et je voudrais faire un parallèle avec la méthode scientifique. OMI, vous pourriez reformuler cette question, "Comment expérimentez-vous une expérience?"
Les expériences vérifient les hypothèses empiriques (hypothèses) sur l'univers physique. Les tests unitaires testeront les hypothèses sur l'état ou le comportement du code qu'ils appellent. Nous pouvons parler de la validité d'une expérience, mais c'est parce que nous savons, à travers de nombreuses autres expériences, que quelque chose ne va pas. Il n'a pas à la fois de validité convergente et de preuves empiriques . Nous ne concevons pas une nouvelle expérience pour tester ou vérifier la validité d' une expérience , mais nous pouvons concevoir une expérience complètement nouvelle .
Donc, comme les expériences , nous ne décrivons pas la validité d'un test unitaire en fonction de sa réussite ou non à un test unitaire lui-même. Avec d'autres tests unitaires, il décrit les hypothèses que nous formulons sur le système qu'il teste. De plus, comme pour les expériences, nous essayons d'éliminer autant de complexité que possible de ce que nous testons. "Aussi simple que possible, mais pas plus simple."
Contrairement aux expériences , nous avons une astuce dans notre manche pour vérifier que nos tests sont valides autres que la validité convergente. Nous pouvons intelligemment introduire un bogue dont nous savons qu'il devrait être détecté par le test, et voir si le test échoue effectivement. (Si seulement nous pouvions faire cela dans le monde réel, nous dépendrions beaucoup moins de cette chose de validité convergente!) Un moyen plus efficace de le faire est de regarder votre test échouer avant de l'implémenter (l'étape rouge en rouge, vert, refactor ).
la source
Vous devez utiliser le paradigme correct lors de l'écriture des tests.
Vous ne pouvez pas toujours être sûr, mais ils améliorent les tests globaux.
la source
Même si vous ne testez pas votre code, il sera sûrement testé en production par vos utilisateurs. Les utilisateurs sont très créatifs pour essayer de planter votre logiciel et trouver des erreurs même non critiques.
La correction des bogues en production est beaucoup plus coûteuse que la résolution des problèmes en phase de développement. En conséquence, vous perdrez des revenus en raison d'un exode de clients. Vous pouvez compter sur 11 clients perdus ou non gagnés pour 1 client en colère.
la source