Nous avons essayé à plusieurs reprises d'introduire des tests automatisés pour les développeurs dans mon entreprise. Notre équipe QA utilise Selenium pour automatiser les tests d'interface utilisateur, mais j'ai toujours voulu introduire des tests unitaires et des tests d'intégration. Dans le passé, chaque fois que nous l'avons essayé, tout le monde était excité pendant le premier mois ou les deux. Puis, plusieurs mois après, les gens arrêtent tout simplement de le faire.
Quelques observations et questions:
Les tests automatisés fonctionnent-ils réellement? La plupart de mes collègues qui travaillaient dans d'autres entreprises ont essayé et échoué à mettre en œuvre une stratégie de test automatisée. Je n'ai toujours pas vu une société de logiciels réelle qui l'utilise réellement et n'en parle pas seulement. De nombreux développeurs considèrent les tests automatisés comme quelque chose de génial en théorie mais qui ne fonctionne pas en réalité. Notre équipe commerciale aimerait que les développeurs le fassent même avec un coût de 30% de temps supplémentaire (du moins ils le disent). Mais les développeurs sont sceptiques.
Personne ne sait vraiment comment faire correctement des tests automatisés. Oui, nous avons tous lu les exemples de tests unitaires sur Internet, mais les utiliser pour un grand projet est tout autre chose. Le principal coupable est de se moquer de la base de données ou de tout autre élément non trivial. Vous finissez par passer plus de temps à vous moquer qu'à écrire des tests réels. Ensuite, quand cela commence à prendre plus de temps pour écrire des tests que du code, c'est alors que vous abandonnez.
Y a-t-il du bon exemples de tests unitaires/tests d'intégration système utilisés dans des applications Web complexes centrées sur les données? Des projets open source? Notre application est centrée sur les données mais a également beaucoup de logique de domaine. J'ai essayé l'approche du référentiel à un moment donné et je l'ai trouvée assez bonne pour les tests unitaires, mais cela s'est fait au prix de pouvoir optimiser facilement l'accès aux données et cela a ajouté une autre couche de complexité.
Nous avons un grand projet entrepris par 20 développeurs expérimentés. Cela semblerait être un environnement idéal pour introduire les tests unitaires/tests d'intégration.
Pourquoi ça ne marche pas pour nous? Comment l'avez-vous fait fonctionner dans votre entreprise?
La partie la plus difficile de faire des tests unitaires est d'obtenir la discipline d'écrire les tests en premier/tôt. La plupart des développeurs ont l'habitude de plonger dans le code. Cela ralentit également le processus de développement dès que vous essayez de comprendre comment écrire un test pour le code. Cependant, à mesure que vous améliorez les tests, cela s'accélère. Et à cause des tests d'écriture, la qualité initiale du code commence plus haut.
Au début, essayez simplement d'écrire des tests. Ne vous inquiétez pas tellement de vous moquer des choses au début. Gardez les tests simples. Les tests sont du code et peuvent/devraient être refactorisés. Bien que dans ce sens, si quelque chose est difficile à tester, cela pourrait aussi être la conception. TDD pousse à utiliser la plupart des modèles de conception (d'après mon expérience, en particulier le modèle Factory).
Assurez-vous que les tests obtiennent un niveau de visibilité. Intégrez-les dans le processus de publication, lors de la révision du code, demandez-les. Tout bogue trouvé devrait passer un test. Ces choses sont là où TDD brille.
Voici quelques ressources que j'ai trouvées utiles:
http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf
http://www.agitar.com/downloads/TheWayOfTestivus.pdf
Modifier:
Une chose à garder à l'esprit lorsque vous écrivez des tests. Vous n'essayez pas de spécifier quoi que ce soit sur l'implémentation du code, seulement le comportement. Lorsque vous écrivez du code, vous le testez tout le temps. Essayer de l'exécuter avec des instructions de débogage et ainsi de suite. L'écriture de tests formalise cela et fournit un enregistrement des tests que vous avez. De cette façon, vous pouvez vérifier vos fonctionnalités en toute confiance sans ignorer accidentellement un scénario de test dont vous vous êtes souvenu à mi-chemin du processus de développement.
À bien des égards, je suis d'accord avec votre équipe.
La plupart des tests unitaires ont une valeur discutable. Étant donné que la grande majorité des tests semblent être trop simples.
Il est beaucoup plus difficile d'écrire un bon code testable qu'un simple code de travail. Il y a un grand pourcentage de la communauté des développeurs qui croit simplement que cela fonctionne, par rapport à la qualité du code/design en soi. Et un pourcentage encore plus important qui ne sait même pas ce qu'est un code de qualité.
L'écriture du code de test unitaire peut prendre beaucoup plus de temps que le code lui-même.
Trouver comment tester correctement le code le plus compliqué (c'est-à-dire ce que vous êtes vraiment intéressé à tester en profondeur) dépasse les capacités de nombreux développeurs.
La maintenance des tests unitaires prend trop de temps. De petits changements peuvent avoir de grands effets d'entraînement. L'objectif principal des tests unitaires automatisés est de savoir si les modifications ont brisé le code. Cependant, 99% du temps, ce qui finit par casser, ce sont les tests et non le code.
Avec tous les problèmes ci-dessus, il n'y a toujours pas de meilleure façon de pouvoir modifier le code et d'avoir un certain niveau de confiance que quelque chose ne s'est pas cassé de manière inattendue que d'automatiser vos tests.
Certains des éléments ci-dessus peuvent être atténués dans une certaine mesure en ne suivant pas le manuel des tests unitaires.
De nombreux types de conceptions/applications sont mieux testés en automatisant les tests au niveau du module/package. D'après mon expérience, la plupart des erreurs de codage ne sont pas dues au fait que le code d'une classe a été mal codé, mais parce que le codeur n'a pas compris comment leur classe était censée fonctionner avec d'autres classes. J'ai vu beaucoup d'argent pour ce type de test. Mais encore une fois, ces tests sont plus difficiles à écrire que les tests unitaires (niveau classe).
Cela revient vraiment à savoir si les développeurs croient ou non au processus. S'ils le font, ils écriront de bons tests unitaires, trouveront les erreurs tôt et seront les promoteurs. S'ils ne le font pas, leurs tests unitaires seront dans l'ensemble inutiles et ne trouveront aucune erreur et leur théorie des tests unitaires inutiles sera prouvée (dans leur esprit).
L'essentiel est que je n'ai jamais vu l'approche de test unitaire automatisée complète fonctionner pendant plus de quelques mois moi-même, mais l'idée de tests unitaires automatisés persiste bien que nous soyons sélectifs dans ce qui a vraiment besoin de tests. Cette approche a tendance à avoir beaucoup moins de critiques et est plus acceptée par tous les développeurs plutôt que par quelques-uns.
Le principal coupable est de se moquer de la base de données ou de tout ce qui n'est pas simple.
Et il y a votre problème.
Tout le monde explique comment intégrer les tests unitaires dans votre environnement. Comment forcer les gens à le faire suffisamment pour qu'ils voient la valeur pratique et que ça "colle". Mais si c'est super pénible à faire et/ou n'apporte aucun avantage, il ne collera pas.
La suppression d'une base de données devrait être très simple. Au lieu que votre interface utilise un support de base de données pour fournir ses résultats, vous insérez un simple objet codé en dur. Si vous ne pouvez pas faire cela, alors votre conception/architecture a des problèmes. Votre code suppose qu'il va dans une base de données, ou vous n'avez pas l'abstraction d'interface pour le faire varier.
Ce n'est pas simplement une préoccupation de test/qualité. Dès que vous souhaitez changer de fournisseur de base de données, ou aller au cloud à la place, ou prendre en charge des applications mobiles non connectées, votre conception échoue tout simplement. Si vous ne pouvez pas prendre en charge les cas de flexibilité les plus simples, vous ne pouvez certainement pas prendre en charge les choses plus complexes dont votre entreprise aura inévitablement besoin.
Vous devez commencer par quelque chose de petit, simple à automatiser et de grande valeur. Tirez vers le bas des fruits sucrés et bas, et vous pourrez vendre le processus. Montrez comment cela a sauvé quelqu'un d'un appel de fin de soirée ou d'un week-end. Ensuite, vous pouvez vous développer à partir de là.
Pour bien faire des tests automatisés, vous avez besoin de quelqu'un qui est une ressource et un évangéliste, et qui a adhéré à des directions de niveau supérieur.
Traitez votre développement de test automatisé comme tout autre projet agile. Produire régulièrement des tests terminés.
Ajout d'un commentaire: il s'agit davantage d'un problème de gestion. Le code est-il considéré comme "terminé" avant d'être documenté? Avant son enregistrement? Avant d'inclure et de réussir les tests unitaires?
La façon dont vous abordez cela dépend vraiment de votre rôle. Êtes-vous un pair? Si oui, montrez aux autres comment il facilite la réutilisation et la maintenance de votre code. Êtes-vous un lead? Choisissez votre programmeur qui a le plus de problèmes de code et aidez-les à ajouter des tests pour éviter ces problèmes. Êtes-vous un patron? Définissez-le comme une norme selon laquelle "le code n'est pas effectué tant que les tests unitaires ne sont pas entrés et réussis.
Suivez ces règles de base. Tests:
doit fonctionner régulièrement! Vous pouvez exécuter des tests sur chaque build, avant/après chaque check-in, ou juste tous les matins. Le déclenchement automatique est hautement préférable au déclenchement manuel. Parce que même si en théorie, tout le monde dans l'équipe peut être responsable de l'exécution des tests, si ce n'est pas automatisé, cela ne se produit probablement pas assez souvent! Et si vous n'exécutez pas vos tests assez souvent, ils découvrent tous les deux les bogues trop tard, encourageant de nombreux tests cassés, ce qui nous amène au point 2:
Vous ne réussirez toujours que si ces tests, qui s'exécutent désormais régulièrement, ne gênent pas . On entend par tests:
une. ne doit pas prendre trop de temps pour fonctionner (subjectivement) pour la valeur qu'ils fournissent! Faites vos tests rapidement. Ne laissez pas les gens vérifier les tests qui vont être une perte de temps pour les laisser s'exécuter!
b. ne doit pas être peu fiable. Évitez autant que possible les tests multithread. Appliquez des pratiques d'ingénierie à vos tests tout comme votre autre code: en particulier - revoyez le code de vos tests!
c. ne doit pas être plus difficile à réparer et à maintenir que le code réel testé. Votre vitesse de codage va vraiment sucer si un petit changement d'une ligne dans votre base de code vous oblige à corriger 10 tests différents.
Et enfin, la règle numéro 3. Les tests doivent non seulement ne pas fournir de valeur négative, comme dans la règle 2, ils doivent fournir une valeur positive. Tests ...
Une façon populaire de violer la règle n ° 3 est de tester la mauvaise chose . Cela est parfois dû au fait qu'un test est trop volumineux ou trop flou. Mais généralement, cela vient de ne pas tester quelque chose qui intéressera un client et de tester des détails d'implémentation non pertinents. (Mais parfois, tester les détails d'implémentation est également un test efficace - OMI, il suffit de s'entraîner à décider lequel.)
Conclusion: ces règles de base vous indiquent la direction générale d'une discipline de test durable , ce dont vous rêvez désespérément. Lors des tests, demandez-vous si ce test est vraiment durable et maintenable. Rappelles toi:
Les tests sont en fait difficiles. Vous devez vous attendre à ce que les tests de votre équipe soient fondamentalement nul quand vous commencez à écrire des tests . Ne vous découragez pas. Do jetez les anciens tests, chaque fois que vous remarquez qu'ils sont nulles et non durables.
1.
Ça marche vraiment?
Oui, c'est le cas - si cela est fait correctement. Le fait est que les testeurs doivent ajuster et étendre leurs scripts automatisés après que les ingénieurs ont implémenté de nouvelles fonctionnalités.
2.
Personne n'est vraiment expérimenté ou ne sait comment faire correctement les tests automatisés.
Obtenez un consultant (quelqu'un qui sait comment cela se fait correctement). Ou investissez plus de temps. L'alternative est d'avoir une équipe de test plus grande, qui effectue les mêmes tests manuellement (ce qui est sujet aux erreurs).
3.
Nous avons un gros projet avec 20 bons développeurs expérimentés qui y travaillent. Il devrait donc être un excellent environnement pour introduire les tests unitaires/tests d'intégration. Pourquoi ça ne marche pas pour nous? Comment l'avez-vous fait fonctionner dans votre entreprise?
Je ne les qualifierais pas de "bons développeurs expérimentés" s'ils refusent de faire des tests unitaires. Il existe de nombreux excellents articles sur les avantages positifs des tests (tests unitaires et tests d'intégration), et à la fin, cela se résume à combien un bogue coûte à votre entreprise . Par exemple, je travaille dans une entreprise où la qualité compte, les tests unitaires et d'intégration sont donc incontournables. Vous pouvez facilement trouver de nombreux articles qui indiquent que les tests unitaires ne font que réduire le nombre de bogues de 30%! (En fait, il se situe entre 20 et 90%, en moyenne 30%, mais c'est encore beaucoup.)
Pour le faire fonctionner dans votre entreprise, embauchez un consultant ou confiez cette tâche à un ingénieur senior (il lui faudra un certain temps pour le faire). Et puis, forcez tout le monde à respecter les règles.
Une chose que je n'ai pas vu clairement abordée dans les réponses ci-dessus est que les tests unitaires sont essentiellement un bien public et un coût privé. J'ai écrit un blog à ce sujet ici .
Ce qui revient à dire que si une suite de tests profite à l'équipe ou à un développeur individuel, écrit le test est un coût pour celui qui le fait, la plupart du temps.
En bref, à moins que l'écriture du test soit appliquée d'une manière ou d'une autre - et les réponses ci-dessus énumèrent un certain nombre de façons différentes de le faire - il n'y a aucune raison pour un développeur individuel pour ce faire.
Dans une entreprise dans laquelle j'ai travaillé, l'écriture de tests unitaires était une partie obligatoire de la livraison d'une fonctionnalité. Le nouveau code n'a pas été accepté sauf si un test unitaire faisait partie de la validation ou de la nouvelle fonctionnalité - il y avait de brèves révisions de code pour chaque "tâche" donnée au développeur. Il peut être utile de mettre en œuvre une politique similaire sur votre lieu de travail.
Ce sont de nombreuses raisons pour lesquelles l'introduction de tests automatisés peut échouer. Je pense que cela se résume au fait que les programmeurs ont tendance à ne pas changer leurs habitudes de codage et ne sont pas pleinement capables d'embrasser les tests unitaires.
De nombreuses personnes qui souhaitent commencer par des tests automatisés essaient de les introduire pour une base de code existante. Ils essaieront d'écrire des tests d'intégration qui testeront simultanément de nombreuses fonctionnalités de l'application existante. De tels tests d'intégration sont notoirement trop difficiles et trop coûteux à maintenir. Conseil: Introduisez des tests automatisés pour une nouvelle base de code.
Les tests unitaires sont de bons tests à automatiser. Tout ce qui précède (tests d'intégration, tests de composants, tests de système) peut également être testé automatiquement, mais le rapport coûts-avantages diminue rapidement à mesure que plus de fonctionnalités sont testées à la fois. Cet effet négatif est amplifié si vous construisez de tels tests sur des fonctionnalités mal testées. Conseil: Introduisez des tests automatisés au niveau des tests unitaires et construisez des tests d'intégration automatisés sur une base solide de tests unitaires .
D'après les points ci-dessus, une grande partie du succès des tests automatisés dépend de l'efficacité des tests unitaires. Vous avez des tests unitaires efficaces si vous vous sentez productif avec des tests unitaires. Lorsque les gens commencent par des tests unitaires, ils ont tendance à transformer leur code existant et leurs habitudes de codage en tests unitaires. Ironiquement, c'est le moyen le plus difficile d'apprendre les tests unitaires. Les tests unitaires nécessitent également de changer la façon dont vous codez (par exemple en appliquant les principes SOLID ). La plupart des programmeurs arrêtent bientôt d'écrire des tests unitaires parce qu'ils pensent que la courbe d'apprentissage est trop abrupte et trouvent gênant d'enrouler les tests unitaires autour d'un code conçu pas si testable. Conseil: Apprenez les tests unitaires à partir de zéro avec le nouveau code et faites face au fait que vous devez changer vos habitudes de codage.
Il existe de nombreux autres facteurs, mais j'ai trouvé que pour la plupart des programmeurs, il est difficile de changer leur façon de coder. Le code écrit sans test est simplement différent. Si vous ne pouvez pas compresser votre code dans une conception testable, vous échouerez très probablement à écrire des tests unitaires efficaces. Cela détruit le terrain pour des tests automatisés efficaces.
Je l'ai vécu par moi-même et je suis maintenant heureux de travailler dans une entreprise qui a introduit avec succès des tests automatisés. Je pourrais écrire beaucoup plus sur les autres facteurs, mais je pense que les habitudes de codage et les tests unitaires sont les plus importants. Heureusement, il y en a d'autres qui ont plus d'expérience que moi et remplissent les livres de leur savoir-faire. L'un de ces livres est Brownfield Application Development in .NET que je peux vraiment recommander, car vous utilisez la pile technologique Microsoft.
Il est intéressant de noter que l'entreprise est plus pro-test que les développeurs! Il me semble que votre plus grand défi sera de surmonter la résistance de vos développeurs au changement; ils doivent redéfinir leur compréhension de leur travail pour inclure les tests unitaires.
Rien ne peut vous aider davantage que les premiers succès des tests unitaires pour aider vos développeurs à surmonter leur résistance à l'écriture de ces tests. Si vous les incitez à faire quelque chose de nouveau, assurez-vous de pousser d'abord pour quelque chose avec une récompense presque garantie.
@SkipHuffman a abordé ce sujet, mais je vais le dire franchement. Certaines choses sont beaucoup plus adaptées aux tests automatisés que d'autres. Pour la première passe, je voudrais [~ # ~] pas [~ # ~] tester la base de données ou l'interface utilisateur. L'entrée à partir d'une base de données peut être extrêmement difficile à configurer et à démonter. Les tests de sortie de l'interface utilisateur ont tendance à être rapidement interrompus par des modifications de l'apparence qui ne sont absolument pas pertinentes pour vos tests.
Ce que j'appellerais "middleware" est parfait pour les tests unitaires. Code ayant des conditions d'entrée et de sortie clairement définies. Si vous suivez le principe DRY (Don't Repeat Yourself), vous aurez écrit quelques petites classes ou fonctions pour résoudre des problèmes récurrents qui sont uniques à votre application.
Les tests unitaires sont un excellent outil pour limiter le risque de modification des composants internes existants. Écrivez des tests unitaires avant de modifier un composant interne qui a fonctionné pendant longtemps. Ces tests prouvent que la fonctionnalité en cours de fonctionnement est préservée. Lorsque vous avez effectué votre modification et que tous les tests unitaires ont réussi, vous savez que vous n'avez rien cassé "en aval". Si vous trouvez un problème en aval, ajoutez un test unitaire pour cela!
Ron Heifitz dirait pour "résoudre les conflits dans les valeurs que les gens détiennent, ou pour réduire l'écart entre les valeurs que les gens défendent et la réalité à laquelle ils sont confrontés. Le travail adaptatif nécessite un changement de valeurs, de croyances ou de comportements . " Après avoir surmonté la résistance humaine au changement, vous pouvez vous implanter dans des zones de test plus difficiles, le cas échéant.
Une chose à propos des tests automatisés est qu'ils nécessitent que vous écriviez du code pour pouvoir être testé. Ce n'est pas une mauvaise chose en soi (en fait, c'est bon car cela décourage beaucoup de pratiques qui devraient en règle générale être évitées), mais si vous essayez d'appliquer des tests unitaires au code existant, il y a de fortes chances que ce ne soit pas été écrit d'une manière testable.
Des choses comme les singletons, les méthodes statiques, les registres, les localisateurs de services, etc. introduisent des dépendances très difficiles à simuler. Les violations de la loi de Demeter signifient que trop de parties de votre base de code en savent trop sur le fonctionnement d'autres parties de votre base de code, introduisant d'autres dépendances cachées qui peuvent être difficiles à briser. Toutes ces choses rendent difficile l'isolement d'un module du reste de la base de code, et si vous ne pouvez pas tester vos modules isolément, les tests unitaires perdent beaucoup de leur valeur. Si un test échoue, est-ce à cause d'un défaut dans l'unité testée, ou à cause d'un défaut dans l'une de ses dépendances, ou peut-être parce que les données qui sont extraites via une source de données dépendante ne sont pas celles attendues par le rédacteur du test ? Si vous ne pouvez pas remplacer les dépendances par des simulations, l'une d'entre elles est possible.
La plupart des bases de code que j'ai vues qui n'ont pas été construites avec des tests unitaires à l'esprit ont tendance à être intrinsèquement non testables, car les codeurs ont tendance à se concentrer sur le fonctionnement du code comme ils l'attendent plutôt que de faire le travail nécessaire pour garder le couplage lâche et les dépendances explicites . Le code qui a été écrit en pensant aux tests unitaires a tendance à être très différent.
Beaucoup de gens adoptent une approche naïve des tests unitaires lorsqu'ils commencent à le faire pour la première fois, ils pensent qu'ils peuvent simplement écrire une charge de tests pour une base de code existante et tout sera bon, mais cela ne fonctionne jamais de cette façon à cause de les problèmes mentionnés ci-dessus. Ils commencent à découvrir qu'ils doivent procéder à des quantités excessives de configuration dans les tests unitaires pour les faire fonctionner, et les résultats sont souvent discutables car le manque d'isolement dans le code signifie que vous ne pouvez pas rechercher ce qui a causé un échec du test. Ils ont également tendance à commencer à écrire des tests "intelligents" qui démontrent un aspect très abstrait du fonctionnement du système. Cela a tendance à échouer car un test unitaire "intelligent" est une source potentielle de bogues en soi. Le test a-t-il échoué à cause d'un bogue dans le module testé ou à cause d'un bogue dans le test? Un test doit être si atroce et simple qu'il n'y a évidemment aucune possibilité qu'un bogue puisse s'y cacher. En fait, les meilleurs tests durent rarement plus de 2 lignes, la première ligne demandant à l'unité testée de faire quelque chose, la seconde affirmant que ce qu'elle a fait était ce qui était attendu.
Si votre équipe souhaite sérieusement adopter les tests unitaires, il serait imprudent de commencer par un projet existant. Les projets existants de votre équipe sont probablement non testables sans refactorisation majeure. Il vaut mieux utiliser un nouveau projet comme base d'apprentissage sur les tests unitaires, car vous avez une table blanche avec laquelle travailler. Vous pouvez concevoir la nouvelle base de code pour favoriser l'injection de dépendances par rapport aux singletons, registres et autres dépendances cachées, vous pouvez l'écrire pour dépendre des interfaces plutôt que des implémentations, etc. Vous pouvez également (et devriez) écrire les tests à côté du code testé, car l'écriture des tests par la suite entraîne des tests unitaires qui garantissent que le module testé fait ce que vous pensez qu'il devrait être fait plutôt que ceux qui le testent. ce que les spécifications disent qu'il devrait faire.
Une fois que vous aurez gagné en confiance avec les tests unitaires, votre équipe commencera probablement à se rendre compte des failles de leur code existant qui seront des obstacles aux tests unitaires. C'est à ce moment que vous pouvez commencer à refactoriser le code existant pour le rendre plus testable. Ne soyez pas ambitieux et essayez de faire tout cela en même temps, ou essayez de remplacer un système qui fonctionne par un tout nouveau, commencez simplement par trouver les bits de la base de code qui peuvent facilement être testés (ceux qui n'ont pas dépendances ou lorsque les dépendances sont évidentes) et écrivez des tests pour celles-ci. Je sais que j'ai dit qu'écrire un test à côté de code est préférable à l'écriture de tests après, mais même un test écrit plus tard a toujours une valeur comme point de départ. Écrivez les tests comme si vous ne saviez rien sur le fonctionnement de la classe autre que ce que ses spécifications disent qu'elle devrait faire. Lorsque vous exécutez les tests et obtenez des échecs, les spécifications ou l'implémentation sont incorrectes. Vérifiez les deux pour déterminer ce qui ne va pas et mettez à jour le test ou le code en conséquence.
Une fois que vous avez cueilli les fruits bas, votre vrai travail commence. Vous devez commencer à rechercher les dépendances cachées dans votre base de code et à les corriger, une à la fois. Ne soyez pas trop ambitieux à ce stade, contentez-vous de faire un module à la fois, ou même un seul problème dans un module, jusqu'à ce que les obstacles aux tests soient résolus et que vous puissiez passer au bit suivant.
TL: DR: La plupart des gens pensent que les tests sont faciles et vous pouvez facilement adapter les tests au code existant. Ces deux hypothèses sont fausses. Si vous vous lancez dans un projet pour obtenir des tests unitaires dans vos projets avec ces deux faits à l'esprit, vous avez plus de chances de réussir.
Sinon, les initiatives de tests automatisés échoueront probablement. Les tests automatisés sont une compétence, comme beaucoup d'autres compétences en programmation, et si vous n'avez personne avec de l'expérience pour le faire, il n'est pas facile de dire si un test automatisé est un bon test automatisé avec une valeur réelle , ou une mauvaise qui échouera au hasard/nécessitera des mises à jour fréquentes/n'exerce en fait aucun code intéressant.
Si personne n'écoute, peu importe s'ils disent que le test n'est pas bon. (Notez que le pouvoir de leadership n'a pas à être officialisé. Avoir une équipe qui se soucie est bien aussi.)
Les développeurs sont paresseux. Vous devez rendre les choses que vous voulez qu'elles soient faciles à accomplir, et les choses que vous ne voulez pas qu'elles soient plus difficiles à accomplir. Vous devez vous assurer que les bibliothèques de test facilitent les tâches associées à la configuration et au démontage des tests, en particulier la configuration liée à l'environnement, comme les bases de données de test ou similaires. (Se moquer de la base de données est discuté dans certains de ces commentaires mais doit être utilisé avec prudence. Une vraie base de données doit être facile à faire tourner et vous permet de tester l'interaction des composants et des cycles de vie des processus, souvent plus important et plus efficace que les tests unitaires. un accesseur de données individuel.)
Vous devez également vous assurer que vos IDE ont un bon moyen de lancer la suite de tests. Vous devez exécuter la suite de tests souvent afin que les gens remarquent quand elle échoue plutôt que de la laisser s'attarder dans la misère. Les développeurs répondent également bien aux commentaires, par exemple un système d'intégration automatisé annulant leurs modifications s'ils ont réussi un test. Ou, mieux, des commentaires positifs: un système d'intégration automatisé qui détecte les bugs et vous évite de casser des choses.
Tout d'abord, si vos développeurs ne voient pas la valeur de vos tests, c'est probablement parce que vos tests n'ont pas de valeur, pas parce que vos développeurs sont aveugles à leur valeur, ou à la valeur des tests en général. Parmi ses évangélistes, on a tendance à croire que le développement piloté par les tests ne peut pas échouer, il peut simplement être échoué par des développeurs paresseux et paresseux. Je pense que c'est faux et contre-productif.
Lorsque j'ai été initié au développement piloté par les tests, cela signifiait, en fait, écrire un test pour vérifier qu'une méthode qui n'échouera jamais n'échouera jamais. Ce qui est sympa au début, car vous obtenez un joli chèque vert et un sentiment d'accomplissement. Plus tard, après avoir refactorisé le code, vous avez des dizaines de X rouges exaspérants, dont aucun ne dit plus que le code a changé, que les tests ne sont plus valides et que vous avez perdu beaucoup de temps à les écrire.
Vous voulez éviter cela.
Depuis lors, j'ai adopté une approche différente des tests. Au lieu d'une paire d'implémentation d'interface , j'ai une interface , implémentation, test triple . L'interface spécifie le comportement, l'implémentation effectue le comportement, le test vérifie le comportement.
Je suppose que cela semble évident, mais pour moi, cela fait une distinction entre le code dont vous devez prouver le fonctionnement tel que spécifié et le code que vous pouvez tester autant ou aussi peu que vous le jugez approprié. Le code que vous devez prouver est l'interface que vous offrez à l'extérieur; le reste est votre seule préoccupation.
Dans ce cas, je demanderais aux développeurs s'ils voient une division naturelle dans le code où ce type de test serait approprié. Existe-t-il une interface que l'équipe A implémente et que l'équipe B utilise? Dans ce cas, il est dans l'intérêt de l'équipe B de s'assurer que l'interface se comporte comme prévu. Demandez à l'équipe B de rédiger un test pour cela, puis dites à l'équipe A de s'assurer que leur implémentation est conforme au test; ou, si ce n'est pas le cas, et ce n'est pas intentionnel, pour discuter du changement inattendu avec l'autre équipe, afin qu'ils puissent s'y préparer.
Je pense que cela illustrerait la valeur du test. Ce n'est pas une fin en soi, malgré les jolis chèques verts. Il existe pour rendre explicite la promesse faite par un développeur à un autre, et pour s'assurer que la promesse est tenue à la satisfaction des deux.
Je pense que vous devrez peut-être jouer le long match. Une chose que vous pouvez faire pour obtenir une certaine acceptation est d'essayer de tester de manière exhaustive la prochaine fonctionnalité que vous écrivez, puis de suivre le nombre de bogues au fil du temps. Espérons que vous constaterez que les principaux bogues seront détectés tôt (en particulier si vous les associez à la conception pilotée par les tests) et que le nombre de régressions devrait être très faible. Après une période de temps, disons 1 an, comparez les statistiques avec des fonctionnalités non testées en unité de complexité similaire. Si vous pouvez montrer que le nombre de nouveaux bogues et régressions est sensiblement inférieur, vous avez fourni une justification financière et il devient plus difficile pour l'équipe produit de l'ignorer.
J'ai eu une situation où j'ai pu utiliser TDD et les tests unitaires pour une fonctionnalité majeure. Après la fin de la phase de développement, aucun bug n'a été signalé depuis plus de 5 ans. Lorsqu'une nouvelle amélioration - et risquée - a été demandée, j'ai pu l'implémenter et capturer toutes les régressions dans les tests unitaires.
L'ajout de nombreux tests unitaires à un grand projet préexistant est un travail difficile. Si vous avez déjà trouvé un bon cadre de simulation qui fonctionne pour vous, vous devriez avoir résolu le problème le plus difficile.
Je suggère d'essayer d'ajouter des tests lorsque vous ajoutez des fonctionnalités/corrigez des bugs. La correction des bogues étant la plus simple. Écrivez un test qui échoue en raison de votre bogue, puis corrigez-le. En même temps, vous vous retrouverez probablement à écrire des tests plus simples qui réussissent. Bien sûr, vous voulez vraiment utiliser un petit morceau de code facile à tester pour cela.
Une fois que les gens commencent à s'habituer à écrire des tests pour les choses les plus faciles, vous devriez espérer qu'ils écrivent leur code pour être plus testable.
Je vous recommande également de mesurer la couverture du code de vos tests (j'ai utilisé cobertura pour Java dans le passé). Vous voudrez en avoir serveur d'intégration exécutant les tests et produisant les métriques sur une base régulière (tous les jours, à chaque enregistrement). Si vos collègues développeurs sont désireux, ils voudront voir l'augmentation de la couverture au fil du temps et ils peuvent voir les trous de couverture béants dans certains de votre
Je suis convaincu que la valeur des tests unitaires est largement sous-estimée par de nombreuses équipes en raison de plusieurs facteurs, dont beaucoup ont déjà été mis en évidence dans les réponses.
Souvent, les développeurs sont contraints de "faire avancer les choses", donc prouver qu'un bloc de code fonctionne est une preuve suffisante pour le client. Cela s'applique presque toujours aux sociétés de conseil et à l'assurance qualité humaine: si le client ne nécessite pas de tests unitaires et considère une démonstration en direct suffisante, le client a totalement échoué car il va signer l'approbation du code qui pourrait masquer les défauts.
Les développeurs sont souvent frustrés. Être programmeur est un travail difficile: terminer une tâche et passer à la suivante est satisfaisant, donc tout le monde veut se dépêcher et finir. Jusqu'à ce qu'ils soient frappés par un bus avec un bug majeur qui augmente des mois après le contrôle qualité d'origine. Dans ce scénario, l'AQ automatisée et continue est un problème de gestion plutôt que de développeurs (ils seront toujours payés pour leur travail, peut-être des heures supplémentaires).
Je crois fermement que l'acceptation du modèle de test automatisé est fonction de l '"humanité" des tests en cours. Si vous testez un module Web avec un frontal, vous êtes plus susceptible, malgré des outils tels que Selenium, de remplir le formulaire par vous-même, de voir le résultat et de croire au déterminisme. Vous oublierez de relancer les tests plus tard ou vous serez juste trop paresseux pour refaire d'anciens tests, et c'est pourquoi des bogues sont parfois découverts plus tard. Pour en tirer parti, une forte modularisation du code et des règles strictes de "modification de l'ancien code" se sont avérées acceptables dans un environnement bancaire (dans mon expérience de travail personnelle).
Au lieu de cela, si le développeur est chargé de développer un module de données hautement automatisé et à volume élevé, il sera plus susceptible d'écrire des tests unitaires approfondis et de les soumettre aux lots de tests. En effet, remplir une charge utile XML volumineuse avec des données converties à partir d'une source de données externe (simulée ou non) n'est pas une tâche humaine. Certains développeurs de tests construiront éventuellement une interface utilisateur minuscule et amusante pour ce type spécifique de tests. Lorsque j'ai travaillé à ma thèse de maîtrise, je travaillais sur un bus de journalisation qui traitait plus de 6000 messages syslog par seconde et je devais mesurer la perte et la corruption de paquets: j'ai naturellement écrit des tests unitaires et des tests de stress pour presque tous les composants, en particulier l'analyseur Syslog.
Je crois qu'ils doivent y être contraints. Si vous êtes un client intelligent, vous aurez besoin de vos consultants pour exécuter la suite de tests complète à chaque contrôle qualité. Si vous êtes un bon chef d'équipe, vous pouvez penser à confier la tâche suivante à un développeur intelligent: créer une plate-forme de test interne. Cela n'a rien à voir avec l'antipatterie de la plate-forme d'effets internes, mais à la place, c'est un ensemble de classes d'assistance, de simulateurs de base de données, de configurations, d'analyseurs, de convertisseurs, de couteaux de l'armée suisse pour aider les développeurs à créer des tests en un rien de temps.
Les plates-formes de test actuelles telles que NUnit sont polyvalentes et vous permettent de vérifier les assertions génériques. L'utilisation correcte de l'injection de dépendances et des usines spécifiques au projet aide les développeurs à écrire moins de code pour les tests et à être plus heureux. Je n'ai pas encore eu l'occasion d'expérimenter cela sur un projet complet, je ne peux pas fournir de feedback réel.
Les tests automatisés sont comme le développement de logiciels. Malheureusement, les personnes que vous embauchez pour les tests sont à l'origine destinées à écrire des cas de test, des plans, une stratégie, à suivre le processus d'examen, à tester manuellement et à consigner les bogues.
Dès qu'on leur confie des responsabilités de test automatisé, cela inclut une certaine quantité de développement logiciel. Le problème ici, c'est que les tests automatisés, quels que soient les outils que vous utilisez (et pour l'amour du ciel, ne discutez pas de ce point), ont besoin de maintenance et de mise à jour quotidiennement. Alors que les développeurs changent de code,
non-functional
les tests se séparent, et ne vous attendez pas à ce qu'ils s'exécutent quotidiennement, il faut du temps pour les garder à jour, et bien. Mais n'abandonnez pas, assurez-vous qu'ils sont maintenus.Vous échouez pour ces raisons
if
et une boucle while
. Parce que franchement aucun cours n'enseigne les tests automatisés, ils n'enseignent que les tests manuels.Ceux-ci sont issus de mon expérience de travail pour des entreprises qui prennent très au sérieux les tests automatisés et comprennent que le développement est important en tant qu'ingénieurs de tests automatisés. Et d'après mon expérience de travail pour des gens qui ne savent pas, comprenez la différence, peu importe combien vous leur expliquez.