1ère partie - Les tests intégrés sont une arnaque

De Wiki Agile du @GroupeCESI
Aller à : navigation, rechercher
Auteur : J. B. Rainsberger
Source : Integrated Tests are a Scam: Part 1
Date : 2009

Traducteur : Fabrice Aimetti
Date : 04/09/2011


Traduction :

Le 1er mars 2010, j'ai décidé de remplacer l'expression "tests d'intégration" par "tests intégrés" dans cet article.
Les tests intégrés sont une arnaque, un virus qui s'auto-réplique et qui menace d'infecter votre code source, votre projet et votre équipe avec des promesses de douleur et de souffrance infinies.
Attendez... qu'est-ce-que je suis en train de dire ?
Je le pense vraiment. Je déteste les tests intégrés. Je les hais avec passion. Bien sûr, je dois ici préciser ce que je veux dire par tests intégrés, parce que, comme tout terme dans le monde du logiciel, nous ne sommes probablement pas d'accord sur son sens.
J'utilise le terme test intégré pour parler d'un test dont le résultat (réussite ou échec) dépend de la mise en oeuvre correcte de plus d'un comportement significatif du système.
Moi aussi, je préférerai une définition plus rigoureuse, mais celle-ci fonctionne bien la plupart du temps pour la plupart des codes sources. J'ai un principe simple : je ne souhaite généralement pas me fier à des tests qui pourraient échouer pour diverses raisons. Ces tests génèrent plus de problèmes qu'ils n'en résolvent.
Vous écrivez des tests intégrés parce que vous ne pouvez pas écrire des tests unitaires parfaits. Vous connaissez ce problème : tous vos tests unitaires passent avec succès, mais quelqu'un trouvera une anomalie de toute façon. Parfois, vous pouvez l'expliquer en trouvant un test unitaire évident que vous avez simplement oublié d'écrire, et parfois vous ne le pouvez pas. Dans ce cas, vous décidez d'écrire un test intégré pour vous assurer que votre code impacté fonctionne désormais correctement en passant par le bout de code erroné.
Jusqu'ici, ça n'a pas été difficile. Mais vous allez bientôt découvrir la monstruosité en réfléchissant à ceci :
Si nous pouvons trouver des anomalies même si nos tests passent avec 100% de succès, et si je peux uniquement rectifier la situation avec des tests intégrés, alors nous ferions mieux d'écrire des tests intégrés pour tout le code.
Mauvaise idée. Très mauvaise idée.
integrated-tests-monster.jpg

Pourquoi si mauvaise ? Un petit peu d'arithmétique simple devrait nous aider à l'expliquer.
Vous travaillez sur une application web de taille moyenne avec environ 20 pages dont 10 comporte des formulaires. Chaque formulaire a en moyenne 5 champs et un champ nécessite en moyenne 3 tests pour être testé à fond. Votre architecture est composé de 10 couches, incluant des widgets de présentation, des pages de présentation, une couche d'abstraction, une passerelle HTTP avec votre API de services, des contrôleurs, des scripts transactionnels, une abstraction des référentiels de données, une implémentation des référentiels de données, un mapping objet-relationnel, des requêtes SQL et une gestion de configuration. Un cycle requête/réponse classique génère une trace de pile d'exécution d'une profondeur de 30 frames, certaines vous les avez écrites et d'autres proviennent d'une grande variété de packages open source et commerciaux sur étagère. De combien de tests avez-vous besoin pour tester cette application à fond ?
Au minimum 10000. Peut-être un million. Un million.
Comment est-ce possible ?![1]
Considérez 10 couches avec potentiellement 3 branches à chaque couche. Nombre de chemins possibles : 310 soit 59000. Avec 4 branches par couche, 410 soit 1000000. Avec 3 branches et 12 couches, 312 soit 530000.

Même si une de nos 12 couches comporte une seule branche, on a 311 soit 177000 chemins possibles. Même si votre application en 10 couches a seulement une moyenne de 3,5 chemins possibles par couche, on a 3,510 soit 275000 chemins possibles au total[2] .
Pour simplifier les calculs, supposez que vous avez uniquement besoin de 100000 tests intégrés pour couvrir votre application. Les tests intégrés mettent généralement en jeu le système de fichiers ou une connexion réseau, ce qui signifie qu'ils passent à un rythme moyen de 50 tests par seconde, pas plus. Votre suite de 10000 tests intégrés va donc s'exécuter en 2000 secondes soit 34 minutes. Cela signifie que vous exécutez entièrement votre suite de tests uniquement lorsque vous vous sentez prêt à versionner vos modifications[3] . Certaines équipes optimistes laissent leur serveur de build continu exécuter ces tests, et perdent un temps précieux lorsque le build échoue et qu'elles prennent une heure pour faire retour arrière.
En combien de temps écrivez-vous 100000 tests ? Si cela prend 10 minutes pour écrire chaque test - en tenant compte du temps de réflexion, du temps consacré au bidouillage pour faire passer le test la première fois et du temps de maintenance de la base de données de tests, du serveur web de tests, du serveur d'application de tests, etc. - cela prendra 2778 journées de 6 heures pour un individu (ou pour un binôme si vous programmez en binôme). Cela équivaut à 556 semaines de 5 jours pour un individu (ou pour un binôme).
Même si je surestime d'un facteur de cinq, vous aurez encore besoin de deux testeurs à plein temps sur un projet d'un an en supposant un flux constant de travail pour les tenir occupés six heures par jour et que vous n'avez pas besoin de corriger les tests parce que vous n'aurez pas le temps de les réécrire.
Non. En fait, vous aurez des testeurs qui écrivent du code huit jours par semaine.
Puisque vous n'allez pas écrire tous ces tests, vous allez écrire les tests que vous pouvez. Vous allez écrire des tests couvrant les chemins nominaux et quelques cas d'erreur. Vous ne testerez pas pas les 10 champs du formulaire. Vous ne testerez pas ce qui se passe un 29 février. Vous allez pourrir la base de données au lieu de copier et coller les 70 tests que vous devez soigneusement vérifier. Vous écrirez 50 tests par semaine, soit 2500 tests sur un projet d'un an. Pas 100000.
2,5% du total des tests que vous deviez écrire pour tester votre application à fond.
Même si ces 2,5% représentent les tests les plus importants, et en supposant que les tests se dupliquent et se complètent à l'infini, vous devriez avoir une couverture comprise entre 10% et 80% du code, et vous ne saurez pas si vous êtes plus proche de 10% ou de 80% jusqu'à ce que le client commence à se battre avec la première version.
Vous sentez-vous chanceux ? Alors ?[4]
Donc, vous écrivez vos 2500 tests intégrés. Peut-être même que vous en écrivez 5000. Lorsque votre client détecte une anomalie, comment allez-vous la corriger ? Et oui, avec une autre série de tests intégrés. Plus vous écrivez des tests intégrés, plus vous cultivez un faux sentiment de sécurité (rappelez-vous que vous venez juste d'augmenter la couverture de votre code de 5% à 5,01%). Ce faux sentiment de sécurité vous aide à vous sentir mieux lorsque vous livrez du code sous-testé à vos clients, ce qui signifie qu'ils trouvent d'autres anomalies, que vous corrigerez encore à l'aide d'autres tests intégrés. Au fil du temps, la couverture de votre code diminuera puisque la complexité de votre code source va augmenter plus vite que votre capacité à écrire assez de tests intégrés pour le couvrir.
... et vous vous demandez pourquoi vous consacrez 70% de votre temps à traiter des demandes du support ?
Les tests intégrés sont une arnaque. Des consommateurs de temps, qui s'auto-répliquent et qui sont peu fiables. Ils doivent disparaître.


  1. NdT : en allemand dans le texte : "Wie ist es möglich?!"
  2. C'est vrai : quelques codes sources distribuent leur complexité sur les couches de façon uniforme. Supposons que la moitié de vos 12 couches a uniquement deux branches possibles - une branche normale et une branche erreur - alors que les autres couches ont 5 branches possibles - alors on a 26 * 56 = 1000000, et pour 4 branches on a 26 * 46 = 262000. Vous ne pouvez pas gagner à ce jeu.
  3. NdT : check-in
  4. Aslak Hellesøy a indiqué un moyen de jouer avec les statistiques. Sa technique pour choisir des tests à forte valeur vous aidera certainement, mais vous ne testerez plus votre code à fond. Je pense que vous pouvez réaliser des tests approfondis avec un coût similaire à écrire et maintenir des tests intégrés en utilisant l'approche de tests par combinaison de deux valeurs (NdT : pairwise tests). Merci Alask pour ton commentaire du 12 avril 2009.