2ème partie - Certains coûts cachés dans les tests d'intégration
Auteur : J. B. Rainsberger
Source : Part 2: Some Hidden Costs of Integration Tests
Date : 2009
Traducteur : Fabrice Aimetti
Date : 04/09/2011
Traduction :
Dan Fabulich : "Je crains que ce premier article de la série ne remette sérieusement en cause la vision que de quelques personnes : l'idée selon laquelle on devrait tester toutes les branches du code en faisant uniquement des tests d'intégration."
Quand je donne mon opinion sur les tests d'intégration aux pratiquants de TDD, certains déforment ce que je dis. Ils soulignent que "personne" ne tente sérieusement de tester un système en entier uniquement avec des tests d'intégration. Même si je comprends cette réaction, je dois préciser que je n'ai jamais déclaré cela. J'observe un comportement qui crée beaucoup plus de dégâts dans les équipes qui pratiquent TDD : ils refont deux fois la même chose en concevant des objets avec des tests ciblés approfondis puis en ajoutant une série de tests d'intégration qui vérifient une partie significative du même comportement. Je comprends pourquoi ils le font. J'avais l'habitude de le faire. Et je veux qu'ils arrêtent de le faire.
Chaque test d'intégration représente un coût... en fait, je ne sais pas précisément vous dire combien ça coûte. Après avoir calculé superficiellement les coûts d'écriture et de maintenance des tests, j'ai très vite perdu la trace des divers effets produits par l'écriture de tests d'intégration à la place, ou même en complément, de tests ciblés sur les objets. Je sais calculer la taxe sur le temps d'exécution des tests d'intégration : un test ciblé s'exécute en moyenne en 4 ms alors qu'un test d'intégration moyen prend près de 100 ms. Je suis à l'aise lorsqu'il s'agit d'estimer une différence selon un ordre de grandeur en base 10. Au-delà, je me perds dans les implications liées à l'écriture de tests d'intégration pour avoir une image claire des coûts. Laissez-moi vous donner un aperçu de ce que je veux dire.
Un conte basé sur deux suites de tests
Considérons deux suites de tests. L'une s’exécute en 6 secondes, et l'autre en 1 minute. Nous supposons qu'elles couvrent la même portion de code de la même manière. Je veux dire qu'elles ont la même capacité à découvrir des erreurs dans le système. Maintenant, imaginez-vous en train d'écrire du code et d'éxécuter la suite de tests qui prend 6 secondes. Vous faites quelques modifications, puis vous exécutez les tests. Que faites-vous pendant les 6 secondes ? Vous prédisez le résultat de l'exécution des tests : ils passeront tous avec succès, ou le nouveau test échouera parce que vous venez juste de l'écrire, ou le nouveau test passera peut-être avec succès parce que vous pensez avoir écrit beaucoup de code depuis 10 minutes. Dans ce laps de temps, vous récupérez votre résultat : les tests sont tous passés avec succès et maintenant vous refactorez le code. Il vous a probablement fallu 6 secondes pour lire jusqu'ici.
Maintenant, imaginez que vous exécutez la suite de tests qui prend 1 minute. Encore une fois, vous prédisez le résultat, période durant laquelle six secondes passent. Si vous travaillez seul, alors après 8 secondes, vous avez commencé à tambouriner des doigts sur le bureau ou laissé vos yeux errer dans la pièce. Vous remarquez la longue liste de tâches sur le tableau de l'équipe. Vous commencez à sentir votre estomac gronder et vous notez qu'il est 11h42. Bientôt l'heure du déjeuner. Vous vous demandez ce qu'il y aura à manger à la cantine, vous ouvrez donc votre navigateur pour regarder sur le site intranet. Des tilapias, c'est pas mal. Vous vous demandez si Lisa se joindra à vous pour le déjeuner, donc vous basculez sur votre client de messagerie. Avant de lui écrire, vous remarquez une notification pour le paiement d'une facture. Vous pouvez payer par carte en 30 secondes, donc vous rebasculer sur votre navigateur pour vous connecter sur votre banque en ligne et effectuer rapidement le paiement. Il s'avère que Lisa a un déjeuner de travail et vous reconsidérer votre choix des poissons. Aujourd'hui, vous décidez qu'il s'agit d'un jour pour le hamburger. Pendant que vous vous imaginez faire cela, plus d'1 minute s'est écoulée. L'ordinateur a consacré une partie de son précieux temps de calcul à vous attendre.
Le binômage ne semble pas résoudre le problème. Si vous avez exécuté cette suite de tests au cours d'une séance de programmation en binôme, alors vous avez probablement passé du temps à bavarder. Au début, vous discuterez du nouveau test. Après un certain temps, vous discutez de la tâche. Cela vous a pris environ 40 secondes, donc vous commencez à dériver sur d'autres sujets : le week-end, les enfants, la XBox, BattleStar Galactica, le baseball, le management, ... puis vous remarquez que l'exécution des tests s'est terminée pendant que vous débattiez si Cliff Lee méritait ou non le trophée Cy Young. Ca ne me gêne pas d'avoir beaucoup de moments de détente dans mon travail, mais lorsqu'on attend plusieurs fois qu'une suite de tests de 1 minute se termine, on en arrive vite à être à court d'histoires à raconter.
Il est nécessaire de souligner le double coût ici. Le premier que nous pouvons facilement voir et mesurer : le temps que nous passons à attendre la fin d'exécution des tests plus le temps que l'ordinateur passe à nous attendre, parce que nous avons du mal à regarder fixement l'exécuteur de tests pendant 60 secondes et à réagir immédiatement une fois qu'il a terminé. Je ne me soucie pas beaucoup de ce coût. Je me soucie plutôt du coût, visible mais difficilement quantifiable, de la perte de concentration.
TDD fonctionne bien pour moi parce qu'il m'aide à me concentrer. Lorsque j'écris un test, je tiens à préciser mon objectif immédiat, en me concentrant sur le fait de le passer avec succès, puis en me concentrant sur le fait d'intégrer ce travail de manière plus appropriée dans la conception. J'arrive à faire celà sur des cycles courts qui exigent une attention soutenue et des moments de récupération de courte durée[1] . Ce cycle de concentration-récupération crée un rythme et ce rythme crée une dynamique. Ce qui contribue au couramment cité et puissant flux de travail. Un test qui s'exécute en 6 secondes offre un moment de récupération après l'effort ; alors qu'un test qui s'exécute en 1 minute perturbe le flux. Il agit comme une interruption courte mais gênante de quelques minutes. Nous pouvons essayer de mesurer l'effet cumulatif de ces interruptions, mais je suppose que vous pouvez vous rappeler d'un jour, récent peut-être, où ces interruptions courtes et périodiques vous ont empêché de vous concentrer. Vous êtes-vous sentis productifs ce jour-là ? Qu'avez-vous réalisé ? Quelle pression avez-vous ressenti le lendemain pour tout rattraper ? Vous êtes-vous senti détendu le soir à la maison ? Avez-vous profité du dîner ? Vous êtes-vous senti disponible pour votre épouse, vos enfants ou votre animal familier ? Avez-vous bien dormi ? Vous êtes-vous senti ressourcé le lendemain matin ?
Parmi les premiers ouvrages TDD, je me souviens distinctement avoir lu que la pratique du TDD m'aiderait à me concentrer, à me détendre, à en faire plus et à me sentir mieux à la fin d'une tâche. Je me souviens avoir souffert sur les tests d'intégration. Des équipes m'ont appelé au secours pour leur apprendre à apprivoiser des suites de tests volumineuses, lentes et instables. Ces équipes ne m'appellent pas lorsqu'elles se sentent concentrées, détendues et productives. Je vous le dis : les tests d'intégration vont lentement vous tuer.
Et maintenant ?
Vous avez désormais des tests d'intégration, et vous n'avez pas encore appris grand chose sur les alternatives possibles. Comment pouvez-vous traiter votre contexte ? Vous pouvez retrouver de la concentration en exécutant les 10% de tests les plus importants. Cela prendrait 6 secondes et s'intégrerait dans votre flux de travail. Cela génère également un risque important d'échec. Vous avez vécu cela. Rappelez-vous la dernière fois que vous avez changé une ligne de code dans une partie du système et que cela a cassé quelque chose dans un autre module ? Comment vous êtes-vous senti lorsque c'est arrivé ? Combien de temps avez-vous passé à traquer une erreur dans les arcanes du système que peut-être personne ne comprend ? Comment vous y êtes-vous pris pour intégrer vos changements dans le code pour traiter le plus gros problème ? Combien de fois avez-vous raconter votre partie de chasse à l'oie sauvage à vos collègues développeurs ? Combien de temps vous a-t-il fallu pour récupérer avant de retrouver un état normal dans votre flux de travail et travailler sur votre tâche initiale ?
Il semble donc que vous ayez un choix à faire entre de fréquentes et gênantes perturbations et de moins fréquentes mais relativement catastrophiques perturbations. Ce qui revient à choisir entre la peste et le choléra. Arrêtez d'écrire des tests d'intégration.
- Pour en savoir plus sur le cycle concentration-récupération, je vous recommande fortement le livre The Power of Full Engagement