Le build est vert. Les tests passent. La couverture est de 87%. Le déploiement est automatisé. Et pourtant, la production brûle. Un client ne peut pas payer. Un utilisateur voit un écran blanc. Un rapport tombe à 3h du matin. Comment ? Le pipeline était vert. Le pipeline est toujours vert. C'est exactement le problème.

Un pipeline vert ne prouve qu'une chose : que vos tests ne testent pas ce qui casse en production. C'est dur à entendre. Mais c'est la vérité que tout le monde évite. On confond "les tests passent" avec "le système marche". Ce sont deux propositions différentes, et la distance entre les deux est exactement la distance entre votre staging et votre production.

Les tests qui ne testent rien

Voici un test que j'ai vu en production, dans une codebase réelle, sur un projet sérieux :

// Un test qui ne teste rien
test('user can login', () => {
    const result = login('user', 'pass');
    expect(result).toBeDefined();
});

Ce test vérifie que la fonction login retourne quelque chose. N'importe quoi. Un objet vide. Une erreur. Un string aléatoire. Le test passe. La couverture de code augmente. Le pipeline est vert. Et personne ne sait si le login marche réellement. Ce n'est pas un cas isolé. C'est la majorité des tests que je vois dans les codebases. Des tests qui vérifient que le code s'exécute sans crasher, pas que le code fait ce qu'il devrait faire.

Un bon test a trois propriétés : il vérifie un comportement spécifique, il échoue quand le comportement est cassé, et il passe quand le comportement est correct. La plupart des tests que je vois ne vérifient que la troisième propriété. C'est inutile. Pire, c'est dangereux, parce que ça donne une fausse confiance.

La couverture mesure les lignes, pas le comportement

87% de couverture de code. Chiffre magique. Les managers adorent. Voici ce qu'il veut dire : 87% des lignes de code sont exécutées pendant les tests. Voici ce qu'il ne veut pas dire : 87% des comportements sont testés. Ce sont deux choses complètement différentes.

Vous pouvez avoir 100% de couverture et zéro test utile. Exécutez chaque fonction avec des entrées aléatoires, vérifiez juste qu'elles ne crashent pas. 100% de couverture. Zéro assertion significative. Le pipeline est vert. La production casse.

La couverture est une métrique de negative space : elle vous dit ce qui n'est pas testé. C'est utile. Mais elle ne vous dit pas ce qui est testé correctement. Utilisez-la pour trouver les zones non testées, pas comme un score de qualité.

Le gap staging-production

"Ça marche en staging." La phrase la plus dangereuse de l'ingénierie logicielle. Staging n'est pas production. Staging a 1% des données de production. Staging a 3 utilisateurs concurrents, pas 3000. Staging a des données de test propres, pas des données de production corrompues par des années de migrations ratées. Staging n'a pas de firewall corporate qui bloque un port aléatoire. Staging n'a pas de DNS qui résoud différemment.

Le gap entre staging et production est le gap entre vos tests et la réalité. Plus le gap est grand, moins vos tests verts signifient quelque chose. Et la plupart des équipes ne mesurent jamais ce gap. Elles assument que staging ≈ production, et elles sont surprises quand ce n'est pas le cas.

La solution n'est pas de faire un staging identique à production (impossible et trop cher). La solution est de tester en production. Oui, en production. Avec des smoke tests, des canary deployments, du feature flagging, du chaos engineering. Parce que la production est le seul environnement qui se comporte comme la production.

Les tests flaky : l'ennemi silencieux

Un test flaky est un test qui passe parfois et échoue parfois, sans changement de code. Au début, on enquête. Après deux semaines, on rerun. Après un mois, on ignore. Après trois mois, on désactive. Le test flaky est le cheval de Troie des pipelines : il habitue l'équipe à ignorer les échecs. Et quand un vrai échec arrive, nobody notices.

Un pipeline où on rerun les tests jusqu'à ce qu'ils passent n'est pas un pipeline. C'est un rituel. La confiance est nulle. Mais le badge est vert, et c'est tout ce que le dashboard montre.

La règle que je donne : un test flaky est un bug. Soit dans le test, soit dans le code. Il doit être traité comme un bug : ticket, investigation, fix. Pas un rerun. Pas un ignore. Un fix. Si vous ne pouvez pas le fixer immédiatement, désactivez-le explicitement avec un commentaire qui explique pourquoi. Mais ne laissez jamais un test flaky dans le pipeline en l'état.

L'environment drift

Staging a Node 20. Production a Node 18. Staging a PostgreSQL 16. Production a PostgreSQL 14. Staging a Redis 7. Production a Redis 6.2. Personne ne sait pourquoi. Personne n'a le temps de mettre à jour. Et un jour, une fonctionnalité utilise une syntaxe de Node 20 qui n'existe pas en Node 18. Le pipeline est vert. La prod casse.

L'environment drift est la raison pour laquelle Docker et les conteneurs existent. Si staging et production utilisent la même image, le drift est impossible. Mais combien d'équipes utilisent réellement les mêmes images en staging et en prod ? Combien pin les versions de manière identique ? Combien ont un process qui vérifie la parité ? Trop peu.

"It works on my machine" est maintenant "It works in staging"

La vieille blague du développeur — "ça marche sur ma machine" — a évolué. Maintenant, c'est "ça marche en staging". C'est la même erreur, déplacée d'un niveau. La machine du développeur n'était pas représentative de la production. Staging non plus. Le pipeline CI est encore moins représentatif, parce qu'il tourne sur des runners éphémères avec des données synthétiques.

La question n'est pas "est-ce que ça marche dans mon environnement ?" mais "est-ce que ça marche dans tous les environnements pertinents ?". Et le seul environnement toujours pertinent, c'est la production.

Un mauvais pipeline vs un bon pipeline

Voici à quoi ressemble un mauvais pipeline :

# Mauvais pipeline : confiance false
stages:
  - name: test
    steps:
      - run: npm install
      - run: npm test  # 200 tests, 50 flaky, 0 assertion utile
      - run: npm run build
  - name: deploy
    steps:
      - run: npm run deploy:staging
      - run: npm run deploy:prod  # pas de smoke test, pas de canary

Et voici un bon pipeline :

# Bon pipeline : confiance réelle
stages:
  - name: test
    steps:
      - run: npm ci  # install déterministe
      - run: npm run test:unit  # tests unitaires rapides
      - run: npm run test:integration  # vraie DB, vraie API
      - run: npm run test:contract  # tests de contrat API
  - name: build
    steps:
      - run: docker build -t app:$VERSION .
      - run: docker push registry/app:$VERSION
  - name: deploy-canary
    steps:
      - run: kubectl set image deployment/app app=registry/app:$VERSION
      - run: kubectl rollout status deployment/app --canary  # 5% du traffic
      - run: npm run test:smoke:prod  # smoke tests en prod sur le canary
  - name: deploy-full
    needs: deploy-canary
    steps:
      - run: kubectl rollout complete deployment/app  # 100% du traffic
      - run: npm run test:smoke:prod  # smoke tests après déploiement complet

La différence ? Le bon pipeline teste le comportement, pas les lignes. Il teste avec une vraie DB. Il déploie progressivement. Il teste en production. Il vérifie que le déploiement marche, pas que le build compile. C'est plus lent, plus complexe, plus coûteux. Mais il vous dit la vérité. Le mauvais pipeline est rapide, simple, et vous ment.

Le rollback que vous n'avez jamais testé

Vous avez un script de rollback. Il est documenté. Il est dans le wiki. Mais l'avez-vous déjà exécuté ? Pas en théorie. Pas en staging. En production. Après un déploiement raté. À 23h. Avec le manager au téléphone.

Le rollback est la dernière ligne de défense. Et c'est souvent la moins testée. Parce que tester un rollback, ça veut dire déployer, casser, rollback, vérifier. C'est un exercice que personne ne fait. Et le jour où on en a besoin, le script a 18 mois, il ne marche plus avec la version actuelle de l'infra, et la base de données a un schéma qui ne peut pas être rollbacké. Game over.

La vérité sur les pipelines verts

Un pipeline vert ne veut pas dire "le système marche". Ça veut dire "rien dans mes tests n'a détecté un problème". Ce sont deux choses différentes. La question n'est pas "est-ce que mes tests passent ?" mais "est-ce que mes tests détectent les problèmes réels ?". Et la seule façon de le savoir, c'est de casser le code et voir si les tests le remarquent.

Et vous ?

Quand avez-vous dernier vérifié que vos tests échouaient quand ils devaient échouer ? Supprimez une ligne critique de votre code, lancez le pipeline. Si le build reste vert, vous avez un problème.

Partager votre retour
Partager : in X f