Tout au vert, et pourtant…
Tu ouvres le terminal. Vingt tests. Vingt coches vertes. Un sentiment de maîtrise, presque de fierté. Puis tu regardes de plus près et tu tombes sur ça :
test('ça marche', () => {
expect(true).toBe(true);
});
Ce test passe toujours. Peu importe ce que ton code fait. Peu importe si tu le supprimes, si tu l'inverses, si tu le remplaces par de la bouillie. true sera toujours égal à true : ce test n'a jamais vu le rouge et ne le verra jamais. C'est un test fantôme : il compte dans le total, il rassure l'œil, et il ne teste absolument rien.
Le piège du faux sentiment de sécurité : un tableau tout au vert peut cacher des tests fantômes, des assertions absentes, ou des tests qui vérifient l'entrée au lieu de la sortie. La couleur verte ne dit pas « mon code est correct ». Elle dit « aucun de ces tests n'a trouvé de problème ». Ce n'est pas la même chose.
Un test qui n'a jamais été rouge ne prouve rien
Voilà la règle que tu dois retenir de cette leçon : un test doit avoir été rouge au moins une fois, et pour la bonne raison. Pourquoi ?
Un test peut passer au vert pour trois mauvaises raisons :
- Pas d'assertion.
test('ça tourne', () => { maFonction(); }): aucunexpect, donc jamais rouge. Il vérifie juste que le code ne plante pas, pas qu'il renvoie quelque chose de juste. - Assertion triviale.
expect(true).toBe(true), ouexpect(result).toBeDefined(): vert tant que la fonction renvoie quelque chose, même une valeur complètement fausse. - Faute de frappe dans le nom. Tu testes
calulerTotal()au lieu decalculerTotal(): la fonction testée n'est pas celle que tu crois, et le test passe vert sur du vide.
Le rouge, lui, prouve deux choses en même temps : que le test sait détecter un problème, et qu'il le détecte pour la bonne raison, pas par accident.
« passer au rouge » ne signifie pas que ton code est mauvais. Ça signifie que ton test est honnête. Le rouge est une bonne nouvelle : il dit « je surveille vraiment quelque chose ».
Le rouge d'abord, en pratique
Voici une fonction vide (un stub) et deux tests déjà écrits. Lance-les : ils sont rouges. La fonction ne renvoie rien, donc elle renvoie undefined, pas true ni false. C'est exactement ce qu'on veut voir d'abord. Ensuite, écris le minimum de code pour les faire passer au vert.
La fonction estPositif est vide (elle ne fait aucun return). Que renvoie-t-elle, et donc que vont afficher les tests au premier lancement ? Écris ta prédiction avant de dérouler.
Voir la réponse
Une fonction sans return renvoie undefined. Les deux tests passent au rouge : le premier attendait true, le second attendait false, tous les deux ont reçu undefined. C'est exactement ce qu'on veut voir d'abord : le rouge prouve que les tests savent détecter l'absence du bon comportement. Ils ne passent pas au vert par accident, ils travaillent vraiment.
Bloqué sur le fix ? Voir la correction
Ajoute return n > 0; dans le corps de la fonction. Une seule ligne suffit : elle renvoie true si n est strictement positif, false sinon. Les deux tests passent au vert. Tu viens de faire exactement ce que fait TDD : le test t'a dit quoi écrire, et tu as écrit le minimum pour satisfaire le contrat.
Écrire le test avant le code
Dans le labo, les tests existaient déjà quand tu as commencé à coder. Tu as vu le rouge, puis tu as écrit le minimum pour le faire disparaître. C'est le principe de base du TDD (Test-Driven Development) : le test vient en premier, le code suit.
Pourquoi écrire le test avant le code ? Parce que le test devient une spécification exécutable. Avant même d'écrire une ligne de logique, tu décris ce que la fonction doit faire. Le test reste rouge tant que ce n'est pas vrai. Quand il passe au vert, tu as fini. Pas de doute, pas de « je crois que ça marche » : le rouge t'a dit que tu n'avais pas fini, le vert te dit que tu as fini.
C'est l'étape RED du cycle TDD : on en parlera en détail à la leçon suivante. Mais retiens déjà l'essentiel :
Avant de faire confiance à un test, vérifie qu'il sait passer au rouge. Casse temporairement le code (change le résultat attendu, vide la fonction, inverse la condition). Si le test reste vert, il ne teste rien. Un test de confiance est un test que tu as déjà vu échouer, pour la bonne raison.
All green, and yet…
You open the terminal. Twenty tests. Twenty green checkmarks. A feeling of control, almost pride. Then you look closer and spot this:
test('it works', () => {
expect(true).toBe(true);
});
This test always passes. Whatever your code does. Whether you delete it, invert it, replace it with gibberish. true will always equal true: this test has never seen red and never will. It's a phantom test — it counts in the total, it reassures the eye, and it tests absolutely nothing.
The false sense of security trap: an all-green board can hide phantom tests, missing assertions, or tests checking the input instead of the output. The green colour doesn't say "my code is correct" — it says "none of these tests found a problem". That's not the same thing.
A test that was never red proves nothing
Here's the rule to take away from this lesson: a test must have been red at least once, and for the right reason. Why?
A test can be green for three wrong reasons:
- No assertion.
test('it runs', () => { myFunction(); })— noexpect, so never red. It only checks the code doesn't crash, not that it returns the right thing. - Trivial assertion.
expect(true).toBe(true), orexpect(result).toBeDefined(): green as long as the function returns something, even a completely wrong value. - Typo in the name. You test
caluateTotal()instead ofcalculateTotal(): the function under test isn't the one you think, and the test goes green on thin air.
Red, on the other hand, proves two things at once: the test knows how to detect a problem, and it detects it for the right reason — not by accident.
"going red" doesn't mean your code is bad — it means your test is honest. Red is good news: it says "I'm really watching something".
Red first, in practice
Here's an empty function (a stub) and two tests already written. Run them: they're red — the function returns nothing, so it returns undefined, not true or false. That's exactly what you want to see first. Then write the minimum code to make them go green.
The isPositive function is empty (no return). What does it return, and what will the tests show on the first run? Write your prediction before expanding.
Show the answer
A function with no return returns undefined. Both tests go red: the first expected true, the second expected false, both received undefined. That's exactly what you want to see first: red proves the tests know how to detect missing behaviour. They don't go green by accident — they're genuinely working.
Stuck on the fix? Show it
Add return n > 0; inside the function body. One line is enough: it returns true if n is strictly positive, false otherwise. Both tests go green. You just did exactly what TDD does: the test told you what to write, and you wrote the minimum to satisfy the contract.
Writing the test before the code
In the lab, the tests existed before you started coding. You saw red, then wrote the minimum to make it disappear. That's the core principle of TDD (Test-Driven Development): the test comes first, the code follows.
Why write the test before the code? Because the test becomes an executable specification. Before writing a single line of logic, you describe what the function must do — and the test stays red until it's true. When it goes green, you're done. No doubt, no "I think it works": red told you you weren't finished, green tells you you are.
This is the RED step of the TDD cycle — we'll cover it in detail in the next lesson. But keep the key takeaway now:
Before trusting a test, check it knows how to go red. Temporarily break the code (change the expected value, empty the function, flip the condition) — if the test stays green, it tests nothing. A trustworthy test is one you've already seen fail, for the right reason.
🎯 Pratique
S'entraîner (clique pour ouvrir) :
💬 Ré-explique sans regarder
Avec tes mots : pourquoi un test qui n'a jamais été rouge ne prouve rien ?
expect(true).toBe(true)), ou faute de frappe dans le nom testé. Le voir rouge une fois prouve qu'il détecte bien le problème, et pour la bonne raison.🧠 Rappel libre
Sans remonter : c'est quoi un test fantôme ? Donne un exemple.
expect(true).toBe(true) (assertion sur une constante), un test sans aucune assertion, ou un test qui vérifie l'entrée au lieu de la sortie. Il compte dans le total vert mais n'apporte aucune garantie.⚖️ Juge le code de l'IA
Pour une fonction qui doit renvoyer 90, l'IA écrit : test('ok', () => { expect(appliquerCoupon(100, 'PROMO10')).toBeDefined(); }) et dit : « C'est testé, c'est vert. » Tu acceptes, ou tu rejettes ?
toBeDefined() est une assertion trop faible : elle passe tant que la fonction renvoie quelque chose, même -900. Ce test serait vert avec un code faux : il n'a jamais pu être rouge pour la bonne raison. Il faut expect(...).toBe(90) : là, le test sera rouge tant que le code est faux, et vert seulement quand il renvoie vraiment 90.expect(true).toBe(true) ?Tu as vu le rouge, tu l'as fait passer au vert. Mais TDD, c'est trois étapes : rouge, vert… et refactor. À la leçon 6, on parcourt le cycle complet, et on pose la vraie question : faut-il vraiment tout faire en TDD ?
Leçon 6 : Le cycle TDD →