Que pouvez-vous faire au sujet de la qualité de l'intégration et des tests unitaires existants tout en étant le nouveau gars d'une équipe?

21

Un thème récurrent que j'ai rencontré dans ma carrière est d'être le nouveau développeur à arriver dans une équipe et d'avoir rapidement une méfiance inhérente envers les suites de tests unitaires et d'intégration existantes.

Au cours de l'entretien, la direction vous dit qu'elle "soutient fortement les tests unitaires" et qu'elle les encourage ouvertement. Ils le font, mais tout ce qui concerne les tests eux-mêmes est tout simplement faux. Comme le fait qu'ils revendiquent une couverture de 100% alors qu'il y a une couverture de test d'intégration de 100% mais une couverture de test unitaire répétable inférieure à 10%. Quelques autres problèmes que j'ai trouvés:

  1. Aucune indication claire entre ce qu'est un test unitaire et ce qu'est un test d'intégration. Les tests unitaires et d'intégration sont mélangés dans la même classe.

  2. Tests d'intégration qui ont des dépendances explicites non déclarées sur des données dynamiques très spécifiques sur la base de données d'un environnement spécifique.

  3. Tests d'intégration non transactionnels, essentiellement des tests qui peuvent ou non prendre la peine de nettoyer après eux-mêmes, nécessitant parfois un "nettoyage" manuel de la base de données pour rendre le test reproductible.

  4. Aucune moquerie du tout, et le code d'application nécessite une refonte majeure juste pour que la moquerie soit possible. En d'autres termes, concevoir sans tester en tête.

  5. Pas de conventions de dénomination claires pour examiner rapidement un nom de test et déterminer approximativement quels tests sont effectués.

Cela ne veut pas dire que TOUS les tests sont inutiles ou mauvais, beaucoup d'entre eux sont assez bons et valent la peine d'être conservés, mais on a parfois l'impression de chercher de l'or. J'éviterais volontairement d'exécuter des tests simplement parce que j'avais peur de bousiller la base de données pour mes cas de test de boîte noire.

Cela m'a essentiellement donné une méfiance inhérente aux tests unitaires et d'intégration que je n'ai pas personnellement écrits ou passés en revue d'une manière ou d'une autre. À un certain niveau, si vous n'avez pas confiance en la qualité de votre suite de tests, cela n'apporte vraiment aucune valeur à l'équipe ou au projet.

Que faites-vous lorsque vous vous trouvez dans cette situation? Selon vous, quel serait le meilleur plan d'attaque pour s'attaquer à quelque chose comme ça?

Tous les tests devraient-ils être refactorisés dans un effort monumental s'étendant sur plusieurs versions? Devriez-vous simplement abandonner l'idée que ce projet hérité peut avoir une couverture de test unitaire solide d'un jour?

maple_shaft
la source
6
Bienvenue dans le monde réel, mon pote.
tdammers
20
Soyez heureux d'avoir des tests.
Joel Etherton
3
Pourquoi travaillez-vous pour des entreprises qui sont clairement au-dessous de votre niveau de compétence?
TrojanName
3
@Brian, j'apprécie le coup de l'ego, mais sans que plus de gens pensent comme moi, ces entreprises ne se dépasseront jamais. C'est la première fois que j'occupe une position de pouvoir réelle, car j'ai développé une modeste importance politique pour une fois. J'ai une réelle opportunité ici de diriger des ressources pour améliorer les choses. Je n'ai pas encore trouvé d'entreprise parfaite sans besoin de travail. C'est comme le mari ou la femme parfait, ils ne viennent pas seulement, une personne assez bonne arrive et ensuite vous les changez en ce que vous voulez qu'ils soient;)
maple_shaft
1
Je pense que nous pourrions travailler pour la même équipe. Maintenant, vous (et moi) savons comment poser des questions lors de nos prochaines interviews. (En fait, mon environnement n'a nulle part près de 100% ou même 10% de couverture de test d'intégration [de vrais tests unitaires? C'est de la folie!], Mais vous avez cloué tous les autres points que je traite.)
Anthony Pegram

Réponses:

6

Tout d'abord, comme d'autres affiches l'ont déjà écrit, vous devriez être heureux que les tests unitaires / d'intégration soient compris (pas de manière technique, je veux dire que la raison pour laquelle cela doit être fait est comprise) et poussés par la direction.

Avant de commencer à tout faire, vous devez exposer les problèmes à la direction, pourquoi quelque chose devrait être fait, et très diplomatiquement afin qu'ils ne pensent pas que vous pensez que vous êtes le meilleur programmeur du monde (même si vous l'êtes! :-). Peut-être qu'ils vous diront que l'application va être remplacée par quelque chose de complètement nouveau, et si oui, pourquoi s'embêter. Et peut-être qu'ils réaliseront que ce serait bien et accélérer la phase de test avant chaque version. Et soyez diplomate avec vos coéquipiers , il peut y avoir des millions de raisons pour lesquelles c'est comme ça et il n'y a tout simplement aucune raison de chercher un coupable.

Une meilleure idée serait d'essayer de leur parler afin qu'ils puissent participer à l'effort, et vous aurez moins de chances d'apparaître comme un cul intelligent, ce serait plus «nous» que «je».

Maintenant, donnez la priorité à ce que vous voulez faire. Prioriser les tâches, en sachant toujours que votre première priorité sera toujours votre mission de projet actuelle ... Quant à votre problème de test, voici ce que je ferais, en trois phases:

  1. Comment faire la différence entre les tests unitaires et d'intégration? Les solutions suivantes peuvent s'appliquer et ne sont pas exclusives:

    • Refactorisez le nom des méthodes de scénario de test (pas les classes car le bon comportement consiste à faire en sorte que le scénario de test partage le même nom que la classe testée)
    • Créez deux annotations, l'une nommée "UnitTest", l'autre "IntegrationTest". Ces annotations peuvent être utilisées sur des classes et sur des méthodes. Si une classe entière est composée de tests unitaires ou d'intégration, vous pouvez marquer la classe avec la bonne annotation. Sinon, vous pouvez marquer chaque méthode avec la bonne annotation. De plus, ces annotations pourraient être utiles pour injecter dynamiquement des fixtures avant de lancer les tests (phase 3)
  2. Pour chaque test d'intégration, indiquez quel est le "jeu de données" qui devrait se trouver dans la base de données au début de chaque test, et ce qui doit être supprimé à la fin de celui-ci (ex: tableau X, a besoin d'un enregistrement avec "id" mis à "1", et "nom" à "foo", etc.). Notez que ce que vous supprimez peut être plus grand / plus petit que ce que vous avez au début car le code lui-même peut respectivement ajouter / supprimer des objets de la couche de persistance. Vous remarquerez très probablement rapidement que plusieurs de ces cas de test nécessitent le même ensemble de données ou une partie du même ensemble de données.

  3. Les deux premières phases peuvent se faire relativement rapidement ... par rapport au reste. Maintenant que vous disposez de votre jeu de données, vous utilisez la création d'appareils de jeu de données pour chaque scénario de test qui en a besoin. Mais cela vous coûtera du temps ... Vous pourriez donc en faire un, voir combien de temps cela vous a coûté et estimer combien de temps vous avez besoin de tout faire. En outre, vous pouvez utiliser ce test pour montrer à vos collègues ce que vous avez fait et pourquoi la vie est tellement plus facile lorsque vous n'avez pas besoin d'avoir une base de données dans un état spécifique pour effectuer des tests.

Vous pouvez noter que les phases 1, 2 et 3 peuvent être effectuées sur une seule classe de test, si vous voulez rapidement montrer aux collègues / à la direction comment cela peut être fait. Cela serait également utile, comme l'a écrit Péter Török, afin de montrer immédiatement la "bonne voie" à vos coéquipiers afin qu'ils arrêtent de produire du mauvais code. Cependant, je pense que le reste de la phase 2, l'identification de l'ensemble des données de test, est mieux fait en une seule grande étape.

Quant à l'API / technologie derrière tout cela, vous semblez connaître le sujet.

J'espère que cela a aidé un peu.

Remarque: pour ma proposition, je suppose que vous codez soit en Java / C # où je sais que les annotations et AOP sont possibles. Je suis sûr que c'est également possible dans d'autres langues, mais je n'écrirai pas sur quelque chose que je ne sais pas.

Jalayn
la source
1
Merci ... J'ai envisagé d'utiliser des annotations comme étiquettes pour identifier ce qu'est un test d'intégration et ce qu'est un test unitaire ... Savez-vous s'il est possible de configurer un serveur CI comme CruiseControl pour exclure certains tests basés sur des annotations? C'est peut-être une question distincte.
maple_shaft
Je suis désolé de ne pas savoir utiliser CruiseControl, donc je ne sais pas à ce sujet. J'ai recherché dans la configuration du plugin Surefire de Maven juste pour la curiosité et cela ne semble pas être possible, mais il est tout à fait possible de sauter des tests basés sur des noms bien sûr.
Jalayn
14

Vous ne pourrez pas corriger tous les tests ensemble. Je pense que vous devriez vous concentrer sur l' amélioration du mot contre la refonte . Ni la direction ni les développeurs ne s'entendront sur une refonte, mais si vous montrez qu'il existe un moyen d'améliorer les choses sans affecter négativement le projet, ils seront plus susceptibles d'écouter.

Tout d'abord, vous ne pouvez pas `` réparer '' ou refactoriser le code existant à moins d'avoir une couverture de test de qualité, donc je me concentrerais sur la réparation de votre infrastructure de test en premier.

Faites une liste des choses qui doivent être améliorées et essayez de les hiérarchiser. Je pense que la possibilité d'exécuter des tests de manière indépendante et individuelle (afin qu'ils ne s'influencent pas mutuellement) et la séparation des tests unitaires et d'intégration sont quelques-unes des premières choses à travailler. Vous devez faciliter la tâche à vous et aux autres.

En ce qui concerne le code d'application ... Vous ne pourrez pas effectuer la refonte complète de l'architecture de l'application juste pour qu'elle puisse être mieux testée à l'unité. Au lieu de cela, lorsque vous insérez du nouveau code, essayez d'appliquer des principes qui facilitent le test unitaire (comme l'injection de dépendances). Vous pourriez penser que ce n'est pas un changement assez important, mais il est étonnant de voir à quelle vitesse les développeurs s'en sortent s'ils voient l'avantage. Il doit juste y avoir quelqu'un qui commence à changer pour le mieux.

Parlez à votre équipe et incitez-la à adhérer. L'une des choses les plus importantes que vous puissiez faire est de suivre la « règle du scoutisme » et d' apporter de petites améliorations pour laisser une classe ou un test dans une meilleure forme que vous l'avez trouvée . Si toute l'équipe applique cette règle, les choses s'améliorent beaucoup plus rapidement.

Après un certain temps, vous aurez beaucoup de code qui suit les bons principes et les domaines de l'application qui sont en mauvais état. À ce stade, vous avez une base de référence de ce qui est bon et l'équipe peut décider s'il est bénéfique de faire un plus grand remaniement pour les anciennes choses héritées ou s'il peut simplement continuer à vivre tel quel.

c_maker
la source
8
+1, et j'ajouterai «commencez par montrer l'exemple». Personne n'apprécie le gars qui entre et dit "vous vous trompez", mais si vous montrez des améliorations, ils seront plus susceptibles de suivre.
StevenV
2
+1 pour la règle du boy-scout , il est beaucoup plus facile à utiliser et à vendre que toute approche de révision.
Matthieu M.
10

Je dois admettre que je considérerais comme un cadeau rare d'arriver à un projet où ils ont déjà un nombre important de tests unitaires / d'intégration - je n'ai jamais eu cette chance dans ma vie jusqu'à présent. Même si tous ne fonctionnent pas comme ils le devraient, beaucoup d'efforts y sont déjà consacrés, et même si l'équipe et la direction ne suivent pas toujours les meilleures pratiques, elles sont déjà engagées dans la cause, donc vous vous n'avez pas besoin de passer votre temps à vous demander pourquoi les tests unitaires méritent d'être écrits.

Cependant, les tests tels que vous les décrivez peuvent effectivement prendre une certaine amélioration. Mais vous devez être prudent avec votre ton lorsque vous discutez des problèmes avec vos coéquipiers . Si vous commencez par dire que "tout ce qui concerne les tests eux-mêmes est tout simplement faux" , vous risquez très vite de vous aliéner le reste de l'équipe. Au lieu de cela, vous devriez vous concentrer sur la façon d'améliorer l'état actuel des choses, qui - je dois le répéter - est encore nettement meilleur que la moyenne selon mon expérience jusqu'à présent.

IMO votre premier objectif devrait être d'empêcher l'équipe de produire plus de mauvais tests . Commencez donc par démontrer l'avantage de chaque amélioration spécifique à vos coéquipiers. S'ils voient l'utilité d'une certaine technique - qu'il s'agisse de couper les dépendances externes, de restaurer l'état d'origine après chaque test ou de séparer les tests unitaires et d'intégration - ils commenceront à les appliquer. En soi, cela améliorera lentement mais sûrement la qualité globale de la base de test à long terme (si vous avez maintenant 1000 cas de test défectueux et que l'équipe produira 1000 bons tests d'ici l'année prochaine, vous aurez fait baisser le ratio de mauvais tests de 100% à 50%). Une fois que cela est sécurisé, vous pouvez décider de refactoriser les tests existants au cas par cas. Encore une fois, de petites améliorations entraîneront de grands changements au fil du temps.

En guise de remarque, d'après le ton de votre message, je pense que vous pourriez être dans un endroit où je l'étais aussi: ne pas faire confiance au travail effectué par d'autres, incapable de déléguer des tâches à quiconque de peur que son travail ne soit pas à la hauteur de votre propres normes de qualité. D'après mon expérience, ce n'est pas un bon endroit où aller, car à long terme, cela peut facilement conduire à des conflits personnels et à l'épuisement professionnel. Vous ne pouvez pas tout faire seul, vous devez travailler avec le reste de l'équipe. Vous ne pouvez réussir qu'ensemble.

Péter Török
la source
6

Travailler à tester l'indépendance. Si le test X modifie la base de données de test de telle sorte que le test Y échoue, changez le test Y. Dans ce petit scénario, la chose à se concentrer n'est pas que X a foiré la base de données, mais plutôt que Y a des dépendances inappropriées. Supprimez ces dépendances (en supprimant la base de données, en restructurant le test ou en initialisant la base de données dans un état où Y passera) et vous avez maintenant un autre test de travail indépendant. C'est un progrès (sans doute, "réparer" X pour ne pas gâcher la base de données ne le serait pas).

Soyez patient et respectueux, du mieux que vous pouvez, des gens avec qui vous travaillez, malgré le désordre qu'ils ont créé. Ils essaient de faire la bonne chose, selon toute vraisemblance; gardez cela à l'esprit et aidez-les à le faire.

Carl Manaster
la source
2
J'aurais dû mentionner qu'aucun des créateurs originaux du mess n'est plus ici. Ils n'avaient pas envie de faire face à la dette technique qu'ils avaient créée et évoluée.
maple_shaft
4
@maple_shaft: C'est bien qu'ils soient partis ... vous pouvez améliorer les choses sans que personne ne perde la face.
Kevin Cline du
2

La bonne chose d'être nouveau dans l'équipe est que vous avez une approche "fraîche" des choses. La mauvaise partie peut être que d'autres peuvent avoir du mal à vous croire.

Ne faites pas de liste de choses à faire. Mais choisissez UNE chose qui semble urgente et à laquelle d'autres sont les plus susceptibles de répondre et de suggérer une solution. Si cela fonctionne, tant mieux, alors suggérez une autre solution à un autre problème, sur la base de votre premier succès.

Mais allez-y lentement, un par un, et espérez que vos idées «progressent» lentement au sein du nouveau groupe.

Tom Au
la source
2

donnez l'exemple que vous voulez voir, mais appréciez la perspective d'un autre développeur dans un test: un développeur peut tester les succès, tandis qu'un autre peut tester les échecs, un développeur a écrit la classe tandis qu'un autre l'a peut-être utilisé la première fois lors de l'écriture du test.

les tests existants (euh, la plupart) ont encore leur utilité, bien que cela ne soit pas immédiatement évident. Je ne recommande pas de réviser et de refactoriser tout à la fois (c'est fastidieux et sujet aux erreurs). les mauvais tests doivent finalement être mis à jour, réécrits, ou ils peuvent simplement devenir obsolètes à mesure que le logiciel évolue.

si votre approche des tests est supérieure à certains égards, les gens apprendront de ce modèle ou vous demanderont votre aide. il y aura un équilibre des ressources, mais vous pouvez étendre au besoin pour prendre en charge vos tests.

au final, vous souhaitez augmenter la qualité des programmes via des tests et améliorer la couverture. vous pouvez le faire en mettant davantage l'accent sur les tests et en donnant un bon exemple - mais appréciez les perspectives des autres.

en soulignant l'importance, vous pouvez rendre l'environnement opérationnel de vos tests différent - un exemple évident est d'exécuter des tests en parallèle; s'il n'est pas réentrant, vous avez localisé un bug dans votre programme ou test (gagnant / gagnant). un environnement de test plus rigoureux obligera les mauvais tests à être corrigés et / ou réécrits (si tout va bien la deuxième fois). introduisez lentement de tels changements (ne cassez pas la moitié des tests d'un coup - c'est un vrai problème), les forçant à apprendre ce qui fait un bon test, et finalement un bon programme. puis lorsque vous et d'autres modifiez / réparez / étendez les tests, appliquez ce que vous avez appris - c'est progressif et vous avez une meilleure compréhension du contexte / programme à l'époque.

Justin
la source
2

Réparez-les au fil du temps

J'ai été dans la même situation. Je viens de passer une heure chaque matin à passer des tests et à les réparer jusqu'à ce qu'ils soient tous réparés. C'était une base de code de taille moyenne et je pense que j'ai terminé en 1,5 mois. Je suis également devenu beaucoup plus confiant dans nos tests.

Personnellement, je m'en fiche si un test est un test unitaire ou un test d'intégration tant qu'il s'agit d'un bon test. Par bon test, je veux dire que:

  • nettoie après lui-même
  • est reproductible
  • minimise les interactions environnementales
  • est consistent

En cours de route, j'ai évangélisé une meilleure construction de test (c'est-à-dire que j'ai énormément mis les gens sur écoute).

Dietbuddha
la source