Aller au contenu principal
TDD a l'ere de l'IA
TDD à l’ère de l’IA : laissez le modèle allumer le feu rouge en premier 的文章封面图

TDD à l’ère de l’IA : laissez le modèle allumer le feu rouge en premier

Assisté par IA

Pourquoi le TDD est-il nécessaire dans la programmation de l'IA ? Le but n'est pas formellement "d'écrire le test en premier", mais de créer un échec vérifiable avant que l'implémentation ne passe du rouge au vert.

Parlons d'abord de la conclusion

Machine à code AI dessinée à la main bloquée par une lumière de test rouge avec un personnage d'avatar d'auteur doré portant des lunettes turquoise à côté
L'IA peut fournir du code rapidement, mais TDD exige qu'elle allume d'abord un feu rouge vérifiable.

Une fois que l'IA a écrit du code, TDD n'est pas obsolète, mais a changé de position.

Dans le passé, lorsque nous parlions de TDD, nous parlions souvent de l'autodiscipline des programmeurs : écrire d'abord les tests, puis écrire l'implémentation et refactoriser par petites étapes. Lorsqu’il s’agit de programmation d’IA, cela s’apparente davantage à un système de freinage. Parce que ce pour quoi le modèle est le meilleur est aussi la chose la plus dangereuse : il peut écrire rapidement un gros morceau de code qui semble complet.

Si vous lui demandez d'implémenter une fonction, il peut vous donner :

  • un dossier d'implémentation
  • une série de tests
  • une explication
  • Un mot "fait"

Le fait est que « avoir l’air complet » n’est pas fait au sens technique du terme. Pour être complété au sens technique, répondez au moins :

Ce comportement est-il défini par un test d'échec explicite ? Cet échec est-il devenu vert grâce à la mise en œuvre ? Après être passé au vert, a-t-on rangé le code sans changer le comportement ?

C’est pourquoi on parle à nouveau de TDD à l’ère de l’IA.

Il ne s’agit pas de donner l’impression que le processus est avancé, mais de remplacer la « confiance dans le modèle » par « la confiance dans le feedback ».

1. Malentendu courant : TDD ne consiste pas à « écrire d'abord les tests »

Bandelette de test dessinée à la main se tournant vers un signal d'échec rouge, personnage d'avatar de l'auteur pointant vers le feu rouge
L'intérêt du TDD n'est pas que les fichiers de test apparaissent tôt, mais que les retours d'échec apparaissent suffisamment tôt.

Beaucoup de gens détestent le TDD parce qu’ils le comprennent comme un rituel :

先写测试。
再写代码。
最后跑一下。

C’est certainement ennuyeux et peut facilement tourner au formalisme.

Le TDD vraiment utile n'est pas "les fichiers de test apparaissent tôt", mais "les échecs apparaissent suffisamment tôt".

La clé n'est pas le test, mais le rouge

La première étape du TDD s'appelle RED, pas TEST.

ROUGE signifie : écrivez d’abord un test pour que le système échoue clairement. Trois choses doivent être vraies pour que cela échoue :

  1. Cela échoue.
  2. Cela échoue parce que le comportement cible n’existe pas.
  3. Cela échoue comme prévu.

Si le rouge n’est pas vu en premier, le vert qui suit n’a aucun sens.

Par exemple, vous souhaitez implémenter slugify("Hello World") -> "hello-world". Un RED précieux n'est pas "J'ai écrit un fichier de test", mais :

Test: tests/test_slugify.py
Command: pytest tests/test_slugify.py -q
Failure: NameError: name 'slugify' is not defined
Reason: 目标函数还不存在,符合预期

C’est à ce moment-là que les tests deviennent des spécifications. Il vous dit : Pour passer à l’étape suivante, il vous suffit de rendre ce comportement vrai.

Passez d'abord au vert, puis rattrapez le test, en inventant généralement l'histoire

Il est facile pour l'IA d'aller dans l'autre sens : écrire d'abord l'implémentation et ajouter des tests plus tard.

C'est une expérience fluide. Lorsque vous verrez que le code a été exécuté et que les tests sont en place, vous vous sentirez « presque » dans votre cœur. Mais il présente un problème fatal : le test ne sera probablement qu’une implémentation rétroactive de l’implémentation actuelle.

Il ne s'agit pas de demander "quelles devraient être les exigences", mais "comment écrire le code actuel pour qu'il puisse être facilement adopté".

C'est pourquoi les tests d'écriture d'IA dégagent souvent ces odeurs :

  • Les assertions sont trop spécifiques à l'implémentation actuelle
  • Il y a trop de simulations et les vraies limites ne sont pas mesurées.
  • testez uniquement le chemin heureux
  • Pour faire passer du code existant, faites des assertions très larges
  • Aucun test ne peut prouver que l'ancien code était erroné à l'origine

TDD exige le contraire : laissez d'abord les exigences échouer, puis laissez le code rattraper les exigences.

2. Pourquoi le TDD est plus nécessaire à l'ère de l'IA

La contradiction fondamentale de la programmation de l’IA n’est pas « le code est écrit lentement », mais « les commentaires arrivent tard ».

Sans TDD, vous travaillez généralement comme ceci :

描述需求 -> AI 写一堆代码 -> 人肉看 diff -> 跑一下 -> 发现问题 -> 回头修

Les questions s'accumuleront jusqu'à la fin. Au moment où vous découvrez que c'est faux, il se peut qu'il y ait trois catégories de choses mélangées :

  • Incompréhension des exigences
  • Le chemin de mise en œuvre est erroné
  • La refactorisation brise l'ancien comportement

Le rôle du TDD est de raccourcir cette longue chaîne.

Cela donne au modèle un objectif décidable

« Écrire avec élégance » n’est pas le but.

"Revenir automatiquement à la page de connexion après l'expiration du statut de connexion de l'utilisateur" n'est pas assez précis.

Un meilleur objectif serait :

当 access token 过期时:
1. 请求返回 401。
2. 客户端清理本地 session。
3. 用户被重定向到 /login。
4. 原始目标地址被保存在 redirect 参数里。

Allez plus loin et transformez l'un d'entre eux en un test d'échec :

given expired session
when user opens /settings
then app redirects to /login?redirect=/settings

À l'heure actuelle, l'IA ne devine plus "comment gérer l'expiration de l'état de connexion", mais complète un comportement clair.

Il divise les grandes tâches en petites boucles fermées

Le moyen le plus simple pour l’IA de perdre le contrôle est de tout faire en une seule fois.

Laissez-le implémenter la connexion, les autorisations, le jeton d'actualisation, les invites d'erreur et les sauts d'itinéraire en même temps, et vous obtiendrez une grosse différence à la fin. Cela pourrait fonctionner, mais le coût de la révision est élevé. Vous devez juger en même temps de l'activité, du statut, du routage, des limites, des tests et de la refactorisation.

Le rythme du TDD ressemble plus à ceci :

一个行为 -> 一个失败测试 -> 最小实现 -> 变绿 -> 再下一个行为

Avancez seulement un petit montant à la fois. Il est suffisamment petit pour que vous puissiez le comprendre, suffisamment petit pour qu’il soit difficile pour l’IA d’inventer des histoires, et suffisamment petit pour qu’elle puisse rapidement localiser en cas d’échec.

Cela limite le modèle à "jouer en douceur"

Un problème courant avec l’IA est l’excès de zèle.

Vous lui demandez de corriger un bug de limite, et il extrait l'assistant ; vous lui demandez d'ajouter un test, et cela modifie l'implémentation ; vous lui demandez de refactoriser et il change son comportement.

TDD utilise des phases pour séparer ces actions :

ÉtapesQue faireCe qu'il ne faut pas faire
ROUGEÉcrire un test d'échecRédiger une implémentation de production
VERTÉcrivez l'implémentation minimaleModifier le test pour devenir vert
RÉFACTEURNettoyer la structureIntroduire de nouveaux comportements

Ce tableau est plus utile que « S'il vous plaît soyez prudent ». Il permet au modèle de savoir à quelle étape il se trouve et permet aux humains de détecter plus facilement les violations des limites.

3. Reconstruction du rouge et du vert : trois portes, pas trois slogans

Trois portes dessinées à la main : feu rouge, vert et reconstruction, avec le personnage avatar de l'auteur tenant un damier
Le refactoring rouge-vert ressemble plus à trois portes : d'abord prouver l'écart, puis laisser passer le comportement actuel, et enfin simplement ranger la structure.

« Rouge, Vert, Refactor » pourrait facilement être un slogan. En utilisation réelle, cela devrait ressembler à trois portes. Chaque fois que vous franchissez une porte, vous devez laisser des preuves.

La première porte : ROUGE, prouvant que les besoins ne sont pas satisfaits

Les questions les plus importantes pendant la phase RED sont :

Si ce test échoue, cela prouve-t-il qu'il nous manque encore un comportement cible ?

UN MAUVAIS ROUGE :

assert True

Pas un très bon RED non plus :

assert "hello" in format_title("Hello World")

C'est trop large. De nombreuses implémentations défectueuses réussissent également.

Meilleur ROUGE :

def test_slugify_lowercases_and_uses_hyphen():
    assert slugify("Hello World") == "hello-world"

Ce test est petit, mais il est clair. Il spécifie les entrées, les sorties et le comportement.

Deuxième porte : VERTE, ne laissez passer que le test en cours

La phase VERTE ne consiste pas à rédiger l’architecture finale.

Il n’a qu’une seule mission : réussir le test actuellement défaillant avec le moins de code possible.

Cette affirmation semble contre-intuitive. Beaucoup de gens se demandent si la « mise en œuvre minimale » ne sera pas trop moche. Oui, parfois, ça peut être moche. Mais sa valeur réside dans le maintien de la pression de conception.

Si le premier test est :

def test_slugify_lowercases_and_uses_hyphen():
    assert slugify("Hello World") == "hello-world"

Un VERT acceptable pourrait simplement être :

def slugify(text: str) -> str:
    return text.lower().replace(" ", "-")

Vous n'avez pas besoin de prendre en charge immédiatement le chinois, les accents, la ponctuation continue, les emoji, les cas spéciaux de référencement. Ceux-ci devraient être pilotés par des tests ultérieurs.

La troisième porte : REFACTOR, ne change que la structure, pas le comportement

L'étape REFACTOR est la plus facile à confondre avec l'IA.

Il interprétera « ranger le code » comme « l'améliorer en passant ». Cela ne fonctionnera pas. La définition du refactoring est très étroite : le comportement externe reste inchangé, mais la structure interne s'améliore.

Une bonne refactorisation ressemble à ceci :

  • Changez le nom de la variable pour un nom plus précis
  • Extraire les expressions répétées
  • Supprimer les branches conditionnelles trop profondes
  • Déplacer les emplacements de fonction pour clarifier les responsabilités des modules

Une mauvaise refactorisation ressemble à ceci :

  • La nouvelle entrée est désormais prise en charge
  • Le message d'erreur a été modifié facilement
  • Modification des dépendances facilement
  • Modification pratique de l'assertion de test

Les critères de jugement sont simples :

Si ce commit s'appelait simplement refactor:, il devrait être du même vert avant et après le test, et le comportement de l'utilisateur devrait être le même.

4. Le goût des bons tests

TDD ne consiste pas à améliorer davantage de tests. L’IA est également très efficace pour générer une série de tests qui ont peu de valeur.

Le plus important est de tester le goût.

Les bons tests sont comme les spécifications

Un bon test doit se lire comme une spécification métier :

当用户没有权限时,保存按钮不可点击。
当标题为空时,表单显示错误信息。
当重复提交同一个请求时,只创建一条记录。

Il s’agit du comportement externe et non de ce qui se fait en interne.

Les mauvais tests ressemblent à des notes d'implémentation :

应该调用 validateInput 三次。
应该读取 state.user.flags。
应该触发 handleClick 内部函数。

Une fois les détails de mise en œuvre réglés, la refactorisation sera pénible. Vous venez de modifier la structure interne, mais les tests ont échoué à grande échelle. Plutôt que de protéger le code, ces tests le gèlent.

Les bons tests ont des limites

Un test est mieux conçu pour répondre à une seule question.

Si un test affirme également :

  • Format correct
  • Les autorisations sont correctes
  • La requête réseau est correcte
  • La copie toast est correcte
  • L'état de la base de données est correct

En cas de panne, il est difficile de savoir quel est le problème.

L’IA est particulièrement encline à rédiger des tests aussi « importants et complets » car elle veut prouver beaucoup de choses à la fois. TDD est le contraire : une action, un échec et une mise en œuvre.

De bons tests rendent difficile la triche des implémentations

Si le test ne couvre qu'une entrée trop spécifique, l'IA peut écrire une fausse implémentation qui correspond juste.

Par exemple :

def slugify(text: str) -> str:
    return "hello-world"

Le premier test permettra de réussir, mais le deuxième test fera ressortir la vraie logique :

def test_slugify_handles_another_title():
    assert slugify("Test Driven Development") == "test-driven-development"

Par conséquent, TDD n'écrit pas toujours un seul test, mais n'ajoute qu'une seule pression comportementale à chaque tour. La pression augmente progressivement et le dessin se développe progressivement.

5. Comment l'IA contournera-t-elle le TDD ?

Trois façons dessinées à la main pour l'IA de contourner le TDD : modification des tests, surajustement et moquerie aléatoire. Le personnage avatar de l'auteur tient une liste de contrôle.
Lorsque l’IA tente de modifier les tests, d’écraser les implémentations ou d’utiliser des simulations pour masquer les limites, le processus doit être ramené aux preuves.

Cette partie doit être précisée car l’IA ne respecte pas naturellement les tests.

Son objectif d'optimisation est simple : terminer la tâche que vous venez de mentionner. Si vous dites « laissez le test réussir », cela peut entraîner certaines actions dont les humains ne veulent pas.

Le premier type : changer le test pour passer au vert

Les plus typiques :

  • Remplacez assert slugify("Hello World") == "hello-world" par la sortie courant
  • Supprimer les assertions ayant échoué
  • Ajouter skip au test
  • Changer les assertions strictes en assertions lâches

Ce n'est pas du TDD, cela éteint le feu rouge.

Le deuxième type : écrire une implémentation de surajustement

Par exemple, le test n'a qu'une seule entrée :

def test_slugify_lowercases_and_uses_hyphen():
    assert slugify("Hello World") == "hello-world"

Le modèle pourrait s'écrire comme suit :

def slugify(text: str) -> str:
    if text == "Hello World":
        return "hello-world"
    return text

Vous n'avez pas besoin de le gronder pour le moment. Vous devez continuer à ajouter le comportement suivant afin que l'implémentation ne puisse pas continuer à être codée en dur.

La troisième méthode : utiliser une simulation pour couvrir la limite réelle

L'IA adore les moqueries. Les simulations facilitent l’écriture des tests et font disparaître de nombreux problèmes réels.

Ce n’est pas qu’on ne peut pas se moquer, mais il faut demander :

Ce dont je me moque maintenant, c'est d'une dépendance lente, ou est-ce une limite que je veux vraiment vérifier ?

Si vous souhaitez vérifier l’analyse des rappels de paiement mais vous moquer de la couche d’analyse, le test n’aura aucun sens.

6. Quand ne pas utiliser TDD

TDD a de la valeur, mais tout n’en vaut pas la peine.

Scène inappropriée

  • Ajustement visuel pur
  • script unique
  • Démo d'exploration technologique
  • Prototypes pour lesquels les exigences elles-mêmes n'ont pas été clairement pensées
  • Le framework de test n'a pas encore mis en place d'entrepôt

Dans ces scénarios, recherchez d’abord la vitesse d’exploration et ne vous laissez pas freiner par le processus.

Scène appropriée

  • corrections de bugs
  • Autorisations, facturation, machine d'état
  • Transformation des données et gestion des limites
  • Des modules de base qui seront maintenus pendant longtemps
  • Chemins de code que l'IA modifiera à plusieurs reprises

La norme de jugement n’est pas « si cette fonction est excellente ou non », mais :

Si c'est faux, les coûts sont-ils évidents ?

Le coût est évident, cela vaut donc la peine de passer le test en premier.

7. Une méthode mentale exécutable

Si je devais donner une seule phrase à l’IA, je ne dirais pas :

请高质量实现这个功能。

Je dirais :

先写一个失败测试,运行它,确认失败原因符合预期。不要写实现,直到我说 go。

Cette phrase est de meilleure qualité car elle ne demande pas au modèle de « bien se comporter » mais plutôt de lui demander d'entrer dans un processus qui peut être vérifié.

Un peu plus complet :

每轮只处理一个行为。
RED:写一个失败测试并运行。
GREEN:写最小实现,不改测试。
REFACTOR:只在绿色状态下整理结构。
每轮报告测试文件、命令、失败原因、通过结果。

C'est le cœur du TDD à l'ère de l'IA.

Pas superstitieux à propos des tests ou des processus, mais à l’idée d’avoir des preuves à chaque étape.

Clôture

Ce dont la programmation de l’IA a le plus besoin, ce n’est pas de plus de code, mais de retours plus courts.

Voici la valeur de TDD : il transforme "Je pensais que ça devrait être juste" en "Voici un échec, puis il est devenu vert". Le changement est minime, mais assez réel.

Si vous ne vous souvenez que d’une seule phrase, souvenez-vous de ceci :

Ne laissez pas l'IA fournir du code directement. Laissez-le d’abord émettre un feu rouge, puis laissez-le passer au vert.

Le prochain article Guide pratique transformera ce rythme en un workflow directement copiable.

Ressources recommandées

TDD, AI agents and coding with Kent Beck
Pragmatic Engineer interviewe Kent Beck. L'accent est mis sur la rétroaction par petites étapes, la protection des tests et la discipline d'ingénierie dans la programmation de l'IA.YouTube

Augmented Coding: Beyond the Vibes

Kent Beck's first-person account of using AI agents while keeping engineering discipline.

Kent BeckTidy First
Visiter

Red/green TDD

Why red/green TDD is a useful compact instruction for coding agents.

Simon Willisonsimonwillison.net
Visiter

Test-Driven Development: By Example

The original book that defined the red-green-refactor loop.

Kent BeckAmazon
Visiter

Commentaires

Table des matières

TDD à l’ère de l’IA : laissez le modèle allumer le feu rouge en premier | Le Bureau Cyber de Yu