Je travaille au développement d'un ancien projet écrit en Java. Nous avons plus de 10 millions de LOC et, pire encore, plus de 4000 tests fonctionnels.
Les tests, programmés par Hudson, échouent comme des fous à chaque changement de code plus important. La vérification de l'échec du test - s'il s'agit d'un problème dans le produit ou dans le test, prend des mois. Nous ne pouvons pas supprimer les anciens tests car nous ne savons pas ce qu'ils testent!
Ce que nous pouvons faire? Comment procéder avec autant de tests hérités?
integration-tests
legacy-code
jenkins
Hector Brosuli
la source
la source
Réponses:
Abandonnez-les.
Je sais qu'il est difficile de laisser tomber quelque chose qui a clairement été beaucoup d'efforts à produire, mais les tests ne fonctionnent pas pour vous, ils travaillent contre vous. Une suite de tests est censée vous donner l'assurance que le système fait ce qu'il est censé faire. S'il ne le fait pas, c'est un passif au lieu d'un actif. Peu importe que le système ou les tests soient en cause - tant que l'exécution de la suite de tests signale d'énormes quantités d'erreurs, elle ne peut pas remplir son objectif.
Ce dont vous avez besoin maintenant, c'est d'une nouvelle suite de tests qui s'exécute sans erreur. Cela signifie qu'il aura initialement peu de couverture, en fait presque pas de couverture. Chaque fois que vous corrigez ou prenez le temps de bien comprendre quelque chose sur votre système, vous réordonnez ces connaissances dans un test. Au fil du temps, cela produira un nouveau filet de sécurité sur lequel vous pourrez vous appuyer à l'avenir. Essayer de réparer un vieux filet de sécurité mal compris est un temps qui ne vaut presque jamais la peine.
Je recommanderais même de ne pas transférer les tests de l'ancienne suite vers la nouvelle suite. Bien sûr, certains d'entre eux peuvent réussir maintenant, mais est-ce parce qu'ils testent exactement ce qu'ils sont censés tester, ou simplement parce que certains tirs aléatoires atteignent toujours la cible? Évidemment, vous devez être pragmatique sur ce qui peut et ne peut pas être fait avec l'effort que vous avez à dépenser, mais vous ne pouvez pas faire de compromis sur le principe qu'une suite de tests doit fonctionner correctement pour faire son travail .
la source
Allez corriger les tests.
Votre plus grande erreur est d'avoir laissé échouer les tests, et vous l'avez évidemment ignoré pendant un certain temps. Ce que vous avez n'est pas des "tests hérités" - vous travaillez sur un code hérité. Et je considère que tout code écrit sans test est hérité.
Il semble qu'il y ait un problème encore plus important dans votre organisation, car vous ne travaillez pas avec des exigences claires. Je ne peux pas comprendre que vous (ou quelqu'un d'autre) ne pouvez pas confirmer le bon comportement.
la source
Les tests sont précieux. À tout le moins, ils enregistrent que quelqu'un considérait qu'ils devraient passer du temps à les écrire, donc ils ont vraisemblablement eu une certaine valeur pour quelqu'un une fois. Avec de la chance, ils contiendront un enregistrement complet de toutes les fonctionnalités et bogues sur lesquels l'équipe a jamais travaillé - bien qu'ils puissent également être un moyen d'atteindre un certain nombre arbitraire de couverture de test sans être soigneusement réfléchi. Jusqu'à ce que vous les regardiez, vous ne saurez pas quel est le cas ici.
Si la plupart de vos tests réussissent la plupart du temps, alors mordez la balle et investissez du temps à déterminer ce que les quelques tests qui échouent tentaient de faire, et à les corriger ou à les améliorer pour que le travail soit plus facile la prochaine fois. Dans ce cas, passez à la section Déterminer l'intention de chaque test pour obtenir des conseils sur la procédure à suivre avec un petit nombre de tests ayant échoué.
D'un autre côté, vous pouvez être confronté à une version rouge maintenant, et à des centaines voire des milliers de tests qui n'ont pas réussi depuis un certain temps, et Jenkins n'a pas été vert depuis longtemps. À ce stade, l'état de la génération Jenkins est devenu inutile et un indicateur clé de problèmes avec votre enregistrement ne fonctionne plus. Vous devez résoudre ce problème, mais vous ne pouvez pas vous permettre d'arrêter tout progrès vers l'avant pendant que vous nettoyez le gâchis dans votre salon.
Afin de garder votre santé mentale tout en effectuant l'archéologie requise pour déterminer quelle valeur peut être récupérée à partir des tests qui ont échoué, je recommanderais les étapes suivantes:
Désactivez temporairement les tests ayant échoué.
Il y a plusieurs façons de le faire, en fonction de votre environnement, que vous ne décrivez pas clairement, donc je ne peux vraiment pas en recommander un en particulier.
Certains cadres prennent en charge la notion de défaillances attendues. Si le vôtre le fait, c'est parfait, car vous verrez un compte à rebours du nombre de tests restant dans cette catégorie, et vous serez même informé si certains d'entre eux commencent à passer de manière inattendue.
Certains frameworks prennent en charge les groupes de tests et vous permettent d'indiquer à Hudson uniquement d'exécuter certains des tests ou d'ignorer un groupe de tests. Cela signifie que vous pouvez occasionnellement exécuter le groupe de tests manuellement pour voir si certains réussissent.
Certains frameworks vous permettent d'annoter ou de marquer autrement des tests uniques à ignorer. Dans ce cas, il est plus difficile de les gérer en groupe, mais cela les empêche de vous distraire.
Vous pouvez déplacer les tests vers une arborescence source qui n'est normalement pas incluse dans la génération.
In extremis, vous pouvez supprimer le code de la TETE du système de contrôle de version, mais cela rendra plus difficile la reconnaissance de la fin de la troisième phase.
L'objectif est d'amener Jenkins à passer au vert dès que possible, afin que vous puissiez commencer à vous déplacer dans la bonne direction dès que possible.
Gardez les tests pertinents.
Décidez d'ajouter de nouveaux tests lorsque vous ajoutez ou modifiez du code, et engagez-vous à conserver tous les tests réussis.
Les tests peuvent échouer pour diverses raisons, notamment le fait qu'ils n'étaient pas des tests bien écrits au départ. Mais une fois que vous avez obtenu Jenkins vert, il est très important de le garder ainsi.
Habituez-vous à écrire de bons tests et faites-en un gros problème si les tests échouent.
Déterminez l'intention de chaque test.
Passez les tests désactivés un par un. Commencez par ceux qui affectent les modules que vous modifiez le plus fréquemment. Déterminez l'intention du test et la raison de l'échec.
Teste-t-il une fonctionnalité qui a été supprimée de la base de code exprès? Ensuite, vous pouvez probablement le supprimer.
Attrape-t-il un bug que personne n'a encore remarqué? Rétablissez le test et corrigez le bogue.
Est-ce qu'il échoue parce qu'il faisait des hypothèses injustifiées (par exemple, en supposant que le texte du bouton serait toujours en anglais, mais maintenant vous avez localisé votre application pour plusieurs langues)? Ensuite, déterminez comment concentrer le test sur une seule chose et isoler le mieux possible des modifications non liées.
Le test s'étend-il à l'ensemble de l'application et représente-t-il un test système? Ensuite, supprimez-le de votre suite de tests Jenkins principale et ajoutez-le à la suite de régression qui s'exécute moins fréquemment.
L'architecture de l'application a-t-elle changé au-delà de la reconnaissance, de sorte que le test n'a plus rien d'utile? Supprime-le.
Le test a-t-il été ajouté pour augmenter artificiellement les statistiques de couverture du code, mais ne fait-il rien de plus que confirmer que le code se compile correctement et ne passe pas dans une boucle infinie? Ou bien, le test confirme simplement que le cadre de simulation sélectionné renvoie les résultats auxquels vous venez de le dire? Supprime-le.
En conséquence, certains tests seront maintenus, certains seront modifiés, certains seront divisés en plusieurs morceaux indépendants de la taille d'une bouchée, et certains seront supprimés. Tant que vous progressez avec de nouvelles exigences, réserver un peu de temps pour faire face à une dette technique comme celle-ci est la chose responsable à faire.
la source
4000 tests est un problème insoluble. 40 tests est plus maniable. Sélectionnez au hasard un nombre gérable de tests à exécuter et à analyser. Classez les résultats comme:
Si de nombreux tests entrent dans la première catégorie, il est peut-être temps de jeter votre suite de tests actuelle et d'en créer une utile pour le code actuel.
Si de nombreux tests échouent de manière à vous signaler un problème dans votre code, vous devez passer par les tests qui échouent en corrigeant les problèmes. Vous pouvez constater que la correction d'un ou deux bogues fait exécuter un grand nombre de tests.
la source
Si cette affirmation est vraie,
cela implique alors que si vous restaurez le code juste avant un "changement de code plus important", de nombreux tests passeront à nouveau. Après cela, récupérez un plus petit bloc de modifications et voyez quels tests échouent récemment. Cela vous aidera à mieux isoler les modifications de code qui provoquent l'échec des tests. Pour chaque test, une fois que vous avez isolé le problème, vous devriez alors pouvoir déterminer si le nouveau code était défectueux ou si le test l'était. S'il s'agit d'un problème avec le nouveau code, assurez-vous de le comparer avec la dernière version au cas où ce bogue particulier aurait déjà été corrigé.
Répétez jusqu'à ce que vous ayez la dernière base de code.
Cela peut sembler une tâche écrasante, mais il est très probable qu'une fois que vous emprunterez ce chemin et commencerez à isoler certains des problèmes, un schéma commencera à émerger, ce qui pourrait accélérer considérablement le processus. Par exemple:
la source
Si vous ne savez pas ce qu'ils testent, supprimez-les jusqu'à ce que vous le sachiez. Les tests sont des choses fluides, si vous supprimez une fonctionnalité qui n'est plus nécessaire, vous devez vous attendre à devoir changer le test qui teste cette fonctionnalité! Donc, à moins que vous ne sachiez ce que les tests testent, vous n'avez aucun espoir de changer la base de code avec eux en place.
Vous pouvez configurer le système de test sur les machines du développeur et y exécuter afin que les développeurs puissent voir avec quelles parties les tests interagissent, avec un peu de chance, fournir cette documentation manquante et se familiariser avec la base de code que vous ne modifiez pas correctement, ou non test plus longtemps correctement.
En bref - si vos anciens tests échouent lorsque vous effectuez des modifications, vos modifications de code ne sont pas bonnes. Utilisez ces tests comme moyen d'éducation sur le fonctionnement du système.
la source
@Ignore
annotation de JUnit - vous pouvez conserver vos tests, mais pas les exécuter. Il s'agit alors simplement de les réactiver et de les réparer un par un. Il vous permet de réduire votre concentration à une poignée de tests à la fois, au lieu d'être submergé par des milliers d'échecs.La chose la plus importante que je ferais serait de revenir aux principes fondamentaux de ce que les tests sont censés faire et de ce que l'entreprise doit continuer de faire. Le travail de test consiste à identifier les problèmes avant qu'ils ne deviennent coûteux à résoudre plus tard. Je pense que le mot clé de cette phrase est "cher". Ces problèmes nécessitent une solution commerciale. Des problèmes coûteux apparaissent-ils sur le terrain? Si c'est le cas, les tests échouent carrément.
Votre gestion et vous devez vous mettre à l'épreuve de la réalité. Vous constatez que les coûts de développement montent en flèche en raison d'un ensemble de tests hérités. Comment ces coûts se comparent-ils aux coûts de livraison d'un produit défectueux parce que vous avez désactivé les tests? Comment se comparent-ils à la lourde tâche de déterminer réellement les comportements dont les utilisateurs ont besoin (quelles sont les choses qui devraient être testées)?
Ce sont des problèmes qui nécessitent des solutions commerciales car ils touchent le côté commercial du travail. Vous livrez un produit à un client, et c'est une frontière qui intéresse beaucoup les entreprises. Ils peuvent être en mesure d'identifier des solutions que vous, en tant que développeur, ne pouvez pas. Par exemple, il peut être raisonnable pour eux de fournir deux produits: un produit "hérité" pour ceux qui ont besoin de fiabilité et qui sont prêts à renoncer à de nouvelles fonctionnalités, avec un produit "visionnaire" qui peut avoir plus de défauts, mais qui ouvre la voie. Cela vous donnerait l'occasion de développer deux ensembles de tests indépendants ... un héritage avec 4000 tests, et un avec plus de tests que vous pensez devoir faire (et les documenter pour que ce processus ne se répète pas).
Ensuite, l'art commence: comment pouvez-vous gérer cette bête à deux têtes afin que les avancées dans une branche aident également l'autre branche? Comment vos mises à jour de la branche "visonary" peuvent-elles refluer vers la branche "legacy", malgré des exigences de test rigides. Comment les demandes continues des clients sur la branche "héritée" peuvent-elles mieux façonner votre compréhension des exigences dont vos anciens clients auraient besoin si vous finissiez par fusionner les produits?
la source
C'est exactement pourquoi vous devriez supprimer les anciens tests! Si vous ne savez pas ce qu'ils font, l'échec n'a aucun sens et les exécuter est une perte de temps. Jetez-les et recommencez.
la source