test-driven-development

Par mkurman · zorai

npx skills add https://github.com/mkurman/zorai --skill test-driven-development

name: test-driven-development description: À utiliser lors de l'implémentation de toute fonctionnalité ou correction de bug, avant d'écrire le code d'implémentation

tags: [development, superpowers, test-driven-development, writing] ------|------|-----| | Minimal | Une seule chose. « et » dans le nom ? Divise-le. | test('validates email and domain and whitespace') | | Clair | Le nom décrit le comportement | test('test1') | | Montre l'intention | Démontre l'API souhaitée | Obscurcit ce que le code devrait faire |

Why Order Matters

« J'écrirai les tests après pour vérifier que ça marche »

Les tests écrits après le code passent immédiatement. Passer immédiatement ne prouve rien :

  • Vous testez peut-être la mauvaise chose
  • Vous testez peut-être l'implémentation, pas le comportement
  • Vous risquez de manquer des cas limites que vous aviez oubliés
  • Vous ne l'avez jamais vu attraper le bug

Test-first vous force à voir le test échouer, prouvant qu'il teste réellement quelque chose.

« J'ai déjà manuellement testé tous les cas limites »

Les tests manuels sont ad-hoc. Vous pensez avoir testé tout, mais :

  • Aucune trace de ce que vous avez testé
  • Impossible de réexécuter quand le code change
  • Facile d'oublier des cas sous pression
  • « Ça a marché quand j'ai essayé » ≠ exhaustif

Les tests automatisés sont systématiques. Ils s'exécutent de la même manière à chaque fois.

« Supprimer X heures de travail est du gaspillage »

Fallacy of sunk costs. Le temps est déjà passé. Votre choix maintenant :

  • Supprimer et récrire avec TDD (X heures supplémentaires, haute confiance)
  • Garder et ajouter des tests après (30 min, faible confiance, bugs probables)

Le « gaspillage » c'est de garder un code en lequel vous ne pouvez pas avoir confiance. Du code qui marche sans vrais tests c'est de la dette technique.

« TDD c'est dogmatique, être pragmatique c'est s'adapter »

TDD EST pragmatique :

  • Trouve les bugs avant le commit (plus rapide que déboguer après)
  • Prévient les régressions (les tests détectent les cassures immédiatement)
  • Documente le comportement (les tests montrent comment utiliser le code)
  • Permet le refactoring (changez librement, les tests détectent les cassures)

Les raccourcis « pragmatiques » = déboguer en production = plus lent.

« Les tests après atteignent les mêmes objectifs - c'est l'esprit qui compte, pas le rituel »

Non. Tests-après répondent « Qu'est-ce que ça fait ? » Tests-first répondent « Qu'est-ce que ça devrait faire ? »

Les tests-après sont biaisés par votre implémentation. Vous testez ce que vous avez construit, pas ce qui est requis. Vous vérifiez les cas limites dont vous vous souvenez, pas ceux découverts.

Les tests-first forcent la découverte des cas limites avant l'implémentation. Les tests-après vérifient que vous vous souvenez de tout (vous ne vous souvenez pas).

30 minutes de tests après ≠ TDD. Vous avez la couverture, vous perdez la preuve que les tests fonctionnent.

Common Rationalizations

Excuse Réalité
« Trop simple pour tester » Le code simple casse. Le test prend 30 secondes.
« Je vais tester après » Les tests qui passent immédiatement ne prouvent rien.
« Les tests après atteignent les mêmes objectifs » Tests-après = « qu'est-ce que ça fait ? » Tests-first = « qu'est-ce que ça devrait faire ? »
« Déjà testé manuellement » Ad-hoc ≠ systématique. Aucune trace, impossible de réexécuter.
« Supprimer X heures c'est du gaspillage » Fallacy of sunk costs. Garder du code non vérifié c'est de la dette technique.
« Garder comme référence, écrire les tests d'abord » Vous l'adapterez. C'est tester après. Supprimer veut dire supprimer.
« Besoin d'explorer d'abord » D'accord. Jettez l'exploration, commencez par TDD.
« Les tests sont durs = design peu clair » Écoutez le test. Dur à tester = dur à utiliser.
« TDD va me ralentir » TDD plus rapide que déboguer. Pragmatique = test-first.
« Les tests manuels sont plus rapides » Les tests manuels ne prouvent pas les cas limites. Vous réitérerez chaque changement.
« Le code existant n'a pas de tests » Vous l'améliorez. Ajoutez des tests pour le code existant.

Red Flags - STOP and Start Over

  • Code avant le test
  • Test après l'implémentation
  • Le test passe immédiatement
  • Impossible d'expliquer pourquoi le test a échoué
  • Tests ajoutés « plus tard »
  • Rationalisation « juste cette fois »
  • « J'ai déjà testé manuellement »
  • « Les tests après ont le même objectif »
  • « C'est une question d'esprit, pas de rituel »
  • « Garder comme référence » ou « adapter le code existant »
  • « J'ai déjà passé X heures, supprimer c'est du gaspillage »
  • « TDD c'est dogmatique, je suis pragmatique »
  • « C'est différent parce que... »

Tous ces signaux signifient : Supprimez le code. Recommencez avec TDD.

Example: Bug Fix

Bug: Email vide accepté

RED

test('rejects empty email', async () => {
  const result = await submitForm({ email: '' });
  expect(result.error).toBe('Email required');
});

Verify RED

$ npm test
FAIL: expected 'Email required', got undefined

GREEN

function submitForm(data: FormData) {
  if (!data.email?.trim()) {
    return { error: 'Email required' };
  }
  // ...
}

Verify GREEN

$ npm test
PASS

REFACTOR Extrayez la validation pour plusieurs champs si nécessaire.

Verification Checklist

Avant de marquer le travail comme terminé :

  • [ ] Chaque nouvelle fonction/méthode a un test
  • [ ] Vous avez vu chaque test échouer avant l'implémentation
  • [ ] Chaque test a échoué pour la bonne raison (feature manquante, pas une typo)
  • [ ] Code minimal écrit pour passer chaque test
  • [ ] Tous les tests passent
  • [ ] Output impeccable (pas d'erreurs, d'avertissements)
  • [ ] Les tests utilisent du vrai code (mocks seulement si inévitable)
  • [ ] Cas limites et erreurs couverts

Impossible de cocher toutes les cases ? Vous avez sauté TDD. Recommencez.

When Stuck

Problème Solution
Ne sais pas comment tester Écrivez l'API souhaitée. Écrivez l'assertion d'abord. Demandez à votre partenaire humain.
Le test est trop compliqué Le design est trop compliqué. Simplifiez l'interface.
Dois mocker tout Code trop couplé. Utilisez l'injection de dépendances.
La configuration du test est énorme Extrayez des helpers. Toujours complexe ? Simplifiez le design.

Debugging Integration

Bug trouvé ? Écrivez un test échouant le reproduisant. Suivez le cycle TDD. Le test prouve la correction et prévient la régression.

Ne jamais corriger un bug sans test.

Testing Anti-Patterns

Quand vous ajoutez des mocks ou des utilitaires de test, lisez @testing-anti-patterns.md pour éviter les pièges courants :

  • Tester le comportement du mock plutôt que du vrai code
  • Ajouter des méthodes test-only aux classes de production
  • Mocker sans comprendre les dépendances

Final Rule

Code de production → test existe et a échoué d'abord
Sinon → pas du TDD

Aucune exception sans la permission de votre partenaire humain.

Skills similaires