Supposons que nous ayons une grande application de niveau entreprise sans tests unitaires/fonctionnels. Il n'y a pas eu de processus de développement piloté par les tests pendant le développement en raison de délais très serrés (je sais que nous ne devrions jamais promettre de délais serrés lorsque nous ne sommes pas sûrs, mais ce qui est fait est fait!)
Maintenant que tous les délais sont passés et que les choses sont calmes, tout le monde a accepté de nous transformer en une équipe productive basée sur TDD/BDD ... Ouais!
Maintenant, la question porte sur le code que nous avons déjà: (1) Est-ce toujours correct ou une bonne idée d'arrêter la plupart du développement et de commencer à écrire des scénarios de test possibles depuis le début, même si tout fonctionne complètement OKAY (encore!) ? Ou (2) il vaut mieux attendre que quelque chose se passe mal, puis pendant le correctif, écrivez de nouveaux tests unitaires, ou (3) oubliez même les codes précédents et écrivez simplement les tests unitaires pour les nouveaux codes uniquement et reportez tout au prochain refactor majeur.
Il y a quelques bons articles connexes tels que celui-ci . Je ne sais toujours pas si cela vaut la peine d'investir dans ce domaine étant donné que nous avons un temps très limité et de nombreux autres projets/travaux nous attendent.
Remarque : Cette question explique/imagine une situation totalement délicate dans une équipe de développement. Cela ne concerne ni moi ni aucun de mes collègues; c'est juste une situation imaginaire. Vous pensez peut-être que cela ne devrait jamais arriver ou que le responsable du développement est responsable d'un tel gâchis! Mais de toute façon, ce qui est fait est fait. Si possible, ne votez pas simplement parce que vous pensez que cela ne devrait jamais se produire.
Il n'y a eu aucun processus de développement piloté par les tests pendant le développement en raison de délais très serrés
Cette déclaration est très préoccupante. Non pas parce que cela signifie que vous avez développé sans TDD ou parce que vous ne testez pas tout. C'est inquiétant, car cela montre que vous pensez que TDD vous ralentira et vous fera manquer un délai.
Tant que vous le voyez de cette façon, vous n'êtes pas prêt pour TDD. Le TDD n'est pas quelque chose que vous pouvez progressivement maîtriser. Soit vous savez comment le faire, soit vous ne le savez pas. Si vous essayez de le faire à mi-chemin, vous allez le faire et vous-même paraître mauvais.
TDD est quelque chose que vous devez d'abord pratiquer à la maison. Apprenez à le faire, car cela vous aide à vous code maintenant . Pas parce que quelqu'un vous a dit de le faire. Pas parce que cela vous aidera lorsque vous apporterez des modifications ultérieurement. Quand cela devient quelque chose que vous faites parce que vous êtes pressé alors vous êtes prêt à le faire professionnellement.
TDD est quelque chose que vous pouvez faire dans n'importe quelle boutique . Vous n'avez même pas à rendre votre code de test. Vous pouvez le garder pour vous si les autres dédaignent les tests. Lorsque vous le faites correctement, les tests accélèrent votre développement même si personne d'autre ne les exécute.
D'un autre côté, si d'autres aiment et exécutent vos tests, vous devez toujours garder à l'esprit que même dans un magasin TDD, ce n'est pas votre travail de vérifier les tests. C'est pour créer un code de production éprouvé. Si cela peut être testé, c'est bien.
Si vous pensez que la direction doit croire en TDD ou que vos collègues codeurs doivent prendre en charge vos tests, vous ignorez la meilleure chose que TDD fasse pour vous. Il vous montre rapidement la différence entre ce que vous pensez que votre code fait et ce qu'il fait réellement.
Si vous ne voyez pas comment cela, à lui seul, peut vous aider à respecter un délai plus rapidement, alors vous n'êtes pas prêt pour TDD au travail. Vous devez vous entraîner à la maison.
Cela dit, c'est bien quand l'équipe peut utiliser vos tests pour les aider à lire votre code de production et quand la direction achètera de nouveaux outils TDD.
Est-ce une bonne idée d'écrire tous les cas de test possibles après avoir transformé l'équipe en TDD?
Peu importe ce que fait l'équipe, ce n'est pas toujours une bonne idée d'écrire tous les cas de test possibles. Écrivez les cas de test les plus utiles. La couverture à 100% du code a un coût. N'ignorez pas la loi des rendements décroissants simplement parce qu'il est difficile d'émettre un jugement.
Économisez votre énergie de test pour la logique métier intéressante. Le truc qui prend des décisions et applique la politique. Testez le diable de cela. Un code de colle structurelle évident et facile à lire qui ne fait que câbler des éléments n'a pas besoin d'être testé aussi mal.
(1) Est-ce toujours correct ou une bonne idée d'arrêter la plupart du développement et de commencer à écrire des cas de test entiers possibles depuis le début, même si tout fonctionne complètement bien (encore!)? Ou
Non, c'est la pensée "faisons une réécriture complète". Cela détruit les connaissances durement acquises. Ne demandez pas à la direction le temps d'écrire des tests. Écrivez simplement des tests. Une fois que vous savez ce que vous faites, les tests ne vous ralentiront pas.
(2) il vaut mieux attendre que quelque chose de mauvais se produise, puis pendant le correctif, écrire de nouveaux tests unitaires, ou
(3) oubliez même les codes précédents et écrivez simplement des tests unitaires pour les nouveaux codes uniquement et reportez tout au prochain refactor majeur.
Je répondrai 2 et 3 de la même manière. Lorsque vous changez le code, pour une raison quelconque, c'est vraiment bien si vous pouvez glisser un test. Si le code est hérité, il n'accueille actuellement pas de test. Ce qui signifie qu'il est difficile de le tester avant de le changer. Eh bien, puisque vous le changez de toute façon, vous pouvez le changer en quelque chose de testable et le tester.
C'est l'option nucléaire. C'est risqué. Vous apportez des modifications sans tests. Il existe quelques astuces créatives pour tester le code hérité avant de le modifier. Vous recherchez ce que l'on appelle des coutures qui vous permettent de modifier le comportement de votre code sans changer le code. Vous modifiez les fichiers de configuration, créez des fichiers, tout ce qu'il faut.
Michael Feathers nous a donné un livre à ce sujet: Travailler efficacement avec le code hérité. Lisez-le et vous verrez que vous n'avez pas à brûler tout ce qui est ancien pour faire quelque chose de nouveau.
Est-ce toujours correct ou une bonne idée d'arrêter la majeure partie du développement et de commencer à écrire des scénarios de test possibles dès le début [...]?
L'héritage donné1 code, écrivez des tests unitaires dans ces situations:
Aussi utiles que soient les tests unitaires, créer une suite de tests unitaires complète pour un1 la base de code n'est probablement pas une idée réaliste. Les pouvoirs en place vous ont poussé à respecter un délai serré. Ils ne vous ont pas laissé le temps de créer des tests unitaires adéquats pendant votre développement. Pensez-vous qu'ils vous donneront suffisamment de temps pour créer des tests pour le "programme qui fonctionne"?
1Le code hérité est le code sans tests unitaires. Il s'agit de la définition TDD du code hérité. Il s'applique même si le code hérité est fraîchement livré [même si l'encre n'a pas encore séché].
D'après mon expérience, les tests n'ont pas besoin d'une couverture totale pour être utiles. Au lieu de cela, vous commencez à récolter différents types d'avantages à mesure que la couverture augmente:
La vérité est que si vous ne commencez pas avec BDD, vous n'y arriverez jamais, car le travail requis pour tester après le codage est tout simplement excessif. Le problème n'est pas d'écrire les tests, mais plus encore d'être conscient de les exigences réelles (plutôt que les détails de mise en œuvre accessoires) et la capacité de concevoir le logiciel d'une manière à la fois fonctionnelle et facile à tester. Lorsque vous écrivez les tests en premier ou avec le code, cela est pratiquement gratuit.
Étant donné que les nouvelles fonctionnalités nécessitent des tests, mais que les tests nécessitent des modifications de conception, mais que la refactorisation nécessite également des tests, vous avez un problème de poule et d'oeuf. À mesure que votre logiciel se rapproche d'une couverture décente, vous devrez effectuer une refactorisation minutieuse dans les parties du code où de nouvelles fonctionnalités se produisent, juste pour rendre les nouvelles fonctionnalités testables. Cela vous ralentira beaucoup - au début. Mais en ne refactorisant et en testant que les pièces où un nouveau développement est nécessaire, les tests se concentrent également sur le domaine où ils sont le plus nécessaires. Le code stable peut continuer sans tests: s'il était bogué, il faudrait quand même le changer.
Pendant que vous essayez de vous adapter à TDD, une meilleure mesure que la couverture totale du projet serait la couverture de test dans les parties qui sont modifiées. Cette couverture devrait être très élevée dès le départ, bien qu'il ne soit pas possible de tester toutes les parties du code impactées par une refactorisation. En outre, vous bénéficiez de la plupart des avantages d'une couverture de test élevée au sein des composants testés. Ce n'est pas parfait, mais tout de même assez bon.
Notez que bien que les tests unitaires semblent être courants, commencer par les plus petites pièces n'est pas une stratégie appropriée pour tester un logiciel hérité. Vous voudrez commencer par des tests d'intégration qui exercent une grande partie du logiciel à la fois.
Par exemple. J'ai trouvé utile d'extraire des cas de test d'intégration à partir de fichiers journaux réels. Bien sûr, l'exécution de tels tests peut prendre beaucoup de temps, c'est pourquoi vous pouvez configurer un serveur automatisé qui exécute les tests régulièrement (par exemple, un serveur Jenkins déclenché par des validations). Le coût d'installation et de maintenance d'un tel serveur est très faible par rapport à la non-exécution régulière de tests, à condition que les échecs de test soient résolus rapidement.
N'écrivez pas de tests pour le code existant. Ça ne vaut pas le coup.
Ce que vous avez fait est déjà quelque peu testé de manière complètement informelle - vous l'avez constamment essayé à la main, les gens ont fait des tests non automatisés, il est utilisé maintenant. Cela signifie que vous ne trouverez pas beaucoup de bugs.
Il ne reste que les bugs auxquels vous n'avez pas pensé. Mais ce sont exactement ceux pour lesquels vous ne penserez pas écrire des tests unitaires, donc vous ne les trouverez probablement pas encore.
En outre, une raison pour TDD est de vous faire réfléchir sur les exigences exactes d'un peu de code avant de l'écrire. De quelque manière que ce soit, vous l'avez déjà fait.
En attendant, écrire ces tests demande toujours autant de travail que cela aurait été le cas auparavant. Cela coûtera beaucoup de temps, pour peu d'avantages.
Et c'est extrêmement ennuyeux d'écrire beaucoup, beaucoup de tests sans codage entre les deux et ne trouvant pratiquement aucun bogue. Si vous commencez à le faire, les nouveaux utilisateurs de TDD --- détestent cela.
En bref, les développeurs le détesteront et les gestionnaires le verront comme coûteux, alors qu'il n'y a pas beaucoup de bogues trouvés. Vous n'obtiendrez jamais à la partie TDD réelle.
Utilisez-le sur les choses que vous souhaitez modifier, dans le cadre normal du processus.
Un test est un moyen de communiquer la compréhension.
Par conséquent, ne rédigez que des tests pour ce que vous comprenez devrait être vrai.
Vous ne pouvez comprendre ce qui devrait être vrai que lorsque vous travaillez avec.
Par conséquent, n'écrivez que des tests pour le code avec lequel vous travaillez.
Lorsque vous travaillez avec le code, vous apprendrez.
Par conséquent, écrivez et réécrivez des tests pour capturer ce que vous avez appris.
Rincez et répétez.
Exécutez un outil de couverture de code avec vos tests et acceptez uniquement les validations sur la ligne principale qui ne réduisent pas la couverture. Finalement, vous atteindrez un niveau de couverture élevé.
Si vous n'avez pas travaillé avec le code depuis un certain temps, une décision commerciale doit être prise. Il est peut-être maintenant si hérité que personne dans votre équipe ne sait comment travailler avec. Il a probablement des bibliothèques/compilateurs/documentation obsolètes, ce qui représente une énorme responsabilité à presque tous égards.
Deux options:
(1) Est-ce toujours correct ou une bonne idée d'arrêter la plupart du développement et de commencer à écrire des cas de test entiers possibles depuis le début, même si tout fonctionne complètement bien (encore!)?
(2) il vaut mieux attendre que quelque chose se passe mal, puis pendant le correctif écrire de nouveaux tests unitaires
L'un des principaux objectifs des tests est de s'assurer qu'un changement n'a rien cassé. Il s'agit d'un processus en trois étapes:
Cela signifie que vous devez avoir des tests de travail avant vous changez réellement quelque chose. Si vous choisissez le deuxième chemin, cela signifie que vous devrez obliger vos développeurs à écrire des tests avant même de toucher le code. Et je soupçonne fortement que lorsqu'ils sont déjà confrontés à un changement réel, les développeurs ne vont pas accorder aux tests unitaires l'attention qu'ils méritent.
Je suggère donc de diviser les tâches d'écriture de test et de modification pour éviter que les développeurs ne sacrifient la qualité de l'un pour l'autre.
même si tout fonctionne parfaitement OKAY (encore!)?
Juste pour le signaler spécifiquement, c'est une idée fausse courante que vous n'avez besoin de tests que lorsque le code ne fonctionne pas. Vous avez également besoin de tests lorsque le code fonctionne, par exemple pour prouver à quelqu'un que [le nouveau bug qui se produit] n'est pas dû à votre partie car les tests sont toujours réussis.
Confirmer que tout fonctionne toujours comme avant est un avantage important des tests que vous omettez lorsque vous indiquez que vous n'avez pas besoin de tests lorsque le code fonctionne.
(3) oubliez même les codes précédents et écrivez simplement des tests unitaires pour les nouveaux codes uniquement et reportez tout au prochain refactor majeur
Idéalement, tout le code source existant devrait maintenant recevoir des tests unitaires. Cependant, il existe un argument raisonnable selon lequel le temps et les efforts (et les coûts) nécessaires pour le faire ne sont tout simplement pas pertinents pour certains projets.
Par exemple, une application qui n'est plus en cours de développement et qui ne devrait plus être modifiée (par exemple, le client ne l'utilise plus ou le client n'est plus un client), vous pouvez faire valoir qu'elle n'est pas pertinente pour tester ce code plus.
Cependant, ce n'est pas aussi clair où vous tracez la ligne. C'est quelque chose qu'une entreprise doit examiner dans une analyse coûts-avantages. Écrire des tests coûte du temps et des efforts, mais s'attendent-ils à un développement futur de cette application? Les gains des tests unitaires l'emportent-ils sur le coût de leur rédaction?
Ce n'est pas une décision que vous (en tant que développeur) pouvez prendre. Au mieux, vous pouvez offrir une estimation du temps nécessaire pour mettre en œuvre des tests sur un projet donné, et c'est à la direction de décider s'il y a une attente suffisante d'avoir réellement besoin de maintenir/développer le projet.
et reporter tout au prochain refactor majeur
Si le prochain refactor majeur est une donnée, vous devez en effet écrire les tests.
Mais ne le remettez pas avant que vous ne soyez confronté à des changements majeurs. Mon point initial (ne pas combiner l'écriture de tests et la mise à jour du code) est toujours valable, mais je veux ajouter un deuxième point ici: vos développeurs actuellement connaissent mieux leur chemin dans le projet qu'ils ne le feront en six mois s'ils passent ce temps à travailler sur d'autres projets. Tirez parti des périodes de temps où les développeurs sont déjà échauffés et n'ont pas besoin de comprendre comment les choses fonctionneront à nouveau à l'avenir.
Mes deux centimes:
Attendez une mise à niveau technique majeure du système et écrivez ensuite les tests ... officiellement avec le support de l'entreprise.
Alternativement, disons que vous êtes un magasin SCRUM, votre charge de travail est représentée par la capacité et vous pouvez allouer un% de cela aux tests unitaires, mais ...
Dire que vous allez revenir en arrière et écrire les tests est naïf, ce que vous allez vraiment faire est d'écrire des tests, de refactoriser et d'écrire plus de tests après que le refactor a rendu le code plus testable, c'est pourquoi il est préférable de commencer avec des tests comme vous le savez déjà, et ...
Il est préférable que l'auteur d'origine écrive des tests et remanie le code qu'ils ont écrit précédemment, ce n'est pas l'idéal, mais d'après l'expérience, vous voulez que le refactoriste améliore le code et n'empire pas.