Au début 2022, j'ai pris une décision discrète : j'ai arrêté d'écrire des tests unitaires pour la plupart des projets WordPress et Node qui passaient par Seahawk. Pas bruyamment. Pas de blog post là-dessus. J'ai juste... arrêté. La justification me semblait solide — nous livrions 15 à 20 sites clients par mois, j'avais trois autres développeurs en rotation, et les tests que j'écrivais ressemblaient à de la documentation que personne ne lisait. L'assurance qualité manuelle attrapait les vrais bugs. Les tests, c'était du théâtre.
Avance rapide jusqu'à fin 2023. GitHub Copilot était dans mon éditeur depuis environ huit mois. J'avais aussi commencé à utiliser Cursor de côté pour tout ce qui était greenfield. La vitesse était véritablement remarquable. Mais quelque chose a commencé à se produire. Des bugs apparaissaient dans des endroits que je n'avais pas touchés. La logique qui semblait correcte était fausse dans des cas limites auxquels je n'avais jamais pensé. Et pire — l'IA ne savait pas qu'elle se trompait. Elle écrivait le code cassé avec la même indentation confiante qu'elle utilise toujours.Cursor on the side for anything greenfield. The speed was genuinely remarkable. But something started happening. Bugs were appearing in places I hadn't touched. Logic that looked correct was wrong in edge cases I'd never thought to check. And the worst part — the AI had no idea it was wrong. It wrote the broken code with the same confident indentation it always does.
C'est à ce moment-là que j'ai repris les tests.
---
La période où j'ai abandonné les tests (et pourquoi ça avait du sens à l'époque)
Réponse honnête ? Pour un certain type de projet, sauter les tests était le bon choix. Si vous construisez un site brochure de cinq pages dans WordPress, écrire des tests PHPUnit pour un plugin de formulaire de contact, c'est du théâtre. Je le maintiens.was the right call. If you're building a five-page brochure site in WordPress, writing PHPUnit tests for a contact form plugin is theatre. I stand by that.
Le cœur de métier de Seahawk pendant longtemps a été exactement ce genre de travail — haut volume, relativement peu complexe, scope bien défini. Un client vous remet un fichier Figma, vous le construisez, vous le testez, vous le livrez. Les boucles de feedback étaient courtes. Si quelque chose cassait, vous le sauriez dans les heures qui suivaient. Écrire des tests pour ce contexte, c'est l'équivalent du développeur de plastifier un Post-it.
Mais j'ai généralisé cette leçon trop agressivement. J'ai commencé à traiter tous les projets comme des sites brochure. Même ceux avec des flux de checkout WooCommerce personnalisés. Même le tableau de bord fintech que nous avons construit début 2023 pour un client à Francfort — API REST entièrement personnalisée, authentification JWT, trois niveaux de permissions utilisateur différents. Pas de tests. Juste « un contrôle qualité manuel attentif ». C'était de l'arrogance, et ça nous a coûté.all projects like brochure sites. Even the ones with custom WooCommerce checkout flows. Even the fintech dashboard we built in early 2023 for a client in Frankfurt — full custom REST API, JWT auth, three different user permission tiers. No tests. Just "careful manual QA." That was arrogant, and it bit us.
Le projet de Francfort a été livré avec un bug de permissions qui permettait aux utilisateurs de niveau éditeur d'interroger des données de niveau administrateur sous une combinaison spécifique de filtres. On ne l'a pas détecté avant que leur équipe interne ne fasse un audit de sécurité six semaines après le lancement. Embarrassant. Réparable. Mais c'est exactement le genre de chose qu'un test d'intégration basique aurait signalé avant même que nous ne créions une pull request.
---
Ce que les outils de codage IA ont vraiment changé
Voici ce que la plupart des gens ratent quand ils parlent de Copilot ou de Cursor ou de quel que soit le modèle qui est tendance ce mois-ci : le code a l'air correct. C'est ça le problème.looks right. That's the problem.
Quand un développeur junior écrit du code bogué, on peut souvent voir l'incertitude dedans. Des noms de variables étranges, un commentaire qui dit // not sure about this, une fonction qui est clairement copy-pastée deux fois. Le code fait passer son propre manque de robustesse. Le code IA ne le fait pas. Il est styliquement cohérent, bien nommé, et structuré d'une façon qui se lit comme intentionnelle. La confiance est entièrement cosmétique.// not sure about this, a function that's clearly copy-pasted twice. The code telegraphs its own fragility. AI code doesn't. It's stylistically consistent, well-named, and structured in a way that reads as intentional. The confidence is entirely cosmetic.
Des études du groupe Human-Computer Interaction de Stanford ont signalé que les développeurs utilisant des assistants IA tendent à accorder trop de confiance au code généré à la première lecture. Ça correspond avec mon expérience personnelle. J'aurais jeté un coup d'œil à une fonction de 40 lignes que Copilot avait écrite, pensé « ouais, c'est à peu près ce que j'aurais écrit », et continué. Parfois c'était correct. Parfois ça avait silencieusement mal compris ce que j'avais vraiment besoin. have flagged that developers using AI assistants tend to over-trust generated code on first read. That tracks with my own experience. I would glance at a 40-line function Copilot had written, think "yeah, that's basically what I'd have written," and move on. Sometimes it was fine. Sometimes it had silently misunderstood what I actually needed.
Le mode de défaillance spécifique que je rencontrais constamment : la logique conditionnelle autour des cas limites que l'IA n'avait aucune raison d'anticiper. Elle écrivait une fonction qui gérait le chemin heureux parfaitement et puis échouait silencieusement sur les entrées null, les arrays vides, ou les formats de date non standard. Des choses qui m'auraient pris trente secondes à penser si j'avais écrit le code moi-même, parce que j'aurais réfléchi en tapant.conditional logic around edge cases the AI had no reason to anticipate. It would write a function that handled the happy path perfectly and then quietly fail on null inputs, empty arrays, or non-standard date formats. Things that would have taken me thirty seconds to think about if I'd written the code myself, because I'd have been thinking as I typed.
Le piège de la vitesse
Il y a un véritable piège de productivité ici. L'IA vous rend rapide. La rapidité semble bonne. Vous commencez à livrer plus vite et vous examinez moins soigneusement parce que la vélocité semble être la preuve de la qualité. Ce n'est pas le cas. La vitesse et la justesse ne sont pas corrélées quand vous utilisez un modèle de langage.
J'ai intégré environ 40 % plus de fonctionnalités dans un projet client en septembre dernier que je n'aurais pu le faire sans l'assistance de l'IA. Le projet contenait aussi plus de bugs post-lancement que n'importe quoi que j'aie livré en deux ans. Pas des bugs catastrophiques. Mais des bugs ennuyeux. Le genre qui érode la confiance du client.
---
Pourquoi les tests fonctionnent différemment maintenant (avec l'IA en boucle)
Quand je suis revenu aux tests, je ne suis pas revenu à l'ancien flux de travail. Écrire les tests en premier, puis l'implémentation, puis la revue de code assistée par l'IA — c'est la boucle dans laquelle je me suis installé maintenant.
La chose intéressante, c'est que l'IA est en réalité excellente pour écrire des tests, d'une manière qu'elle n'est pas toujours excellente pour écrire de la logique applicative. Donnez à Copilot une signature de fonction bien définie et demandez-lui de générer une suite de tests et il produira une couverture des cas limites que j'aurais mis vingt minutes à écrire manuellement. Il imagine bien les chemins malheureux quand la tâche est précisément « trouver comment cela peut se casser ».AI is actually excellent at writing tests, in a way it isn't always excellent at writing application logic. Give Copilot a well-defined function signature and ask it to generate a test suite and it'll produce edge-case coverage I'd have taken twenty minutes to write manually. It imagines unhappy paths well when the task is specifically "find ways this can break."
J'ai donc en quelque sorte inversé la chose. J'écris la spécification des tests. L'IA remplit les cas de test. Ensuite, l'IA écrit l'implémentation. Ensuite, je lis l'implémentation à travers le prisme de ces tests, plutôt que de simplement lire le code à froid.through the lens of those tests, rather than just reading the code cold.
C'est plus lent que du pur vibe-coding. Mais c'est plus rapide que l'ancien flux de travail où tout était écrit manuellement, y compris les tests. Et cela n'a livré zéro bugs de permissions depuis Frankfurt.
Les outils que j'utilise réellement
- [Vitest](https://vitest.dev) pour tout ce qui est JavaScript ou TypeScript. J'ai remplacé Jest entièrement l'année dernière — la configuration est plus saine et le mode watch est rapide. for anything JavaScript or TypeScript. Replaced Jest for me entirely last year — the config is saner and the watch mode is quick.
- PHPUnit encore, pour WordPress et le travail PHP personnalisé. Rien ne l'a remplacé. still, for WordPress and custom PHP work. Nothing has replaced it.
- Le raccourci "test this function" de Cursor — franchement l'une des fonctionnalités les plus utiles que j'ai vues dans un éditeur. — genuinely one of the most useful single features in any editor I've used.
- GitHub Actions pour la CI. Les tests s'exécutent à chaque push sur main. Cela prend environ 90 secondes sur la plupart des projets. for CI. Tests run on every push to
main. Takes about 90 seconds on most projects.
---
L'Argument Contre les Tests (Présenté Honnêtement)
Je veux donner à cette position une chance équitable parce que je l'ai défendue pendant près de deux ans.
Le vrai argument n'est pas « les tests sont inutiles ». C'est « les tests ont un coût et beaucoup de projets ne justifient pas ce coût ». Écrire et maintenir une suite de tests prend du temps. Sur un projet avec une courte durée de vie — un microsite de campagne, une landing page marketing, un prototype de hackathon — ce temps investi ne rapporte rien. Le projet sera mort avant que les tests ne vous sauvent de quoi que ce soit.
Et il y a un point plus subtil : les mauvais tests sont pires que pas de tests du tout. Une suite de tests qui passe parce que les tests sont tautologiques (tu testes essentiellement que ta fonction retourne ce que tu lui as dit de retourner) te donne une fausse confiance. J'ai vu ça dans des agences. Des développeurs qui écrivent des tests qui passent toujours parce que personne n'a remis en question ce qu'ils vérifiaient réellement.bad tests are worse than no tests. A test suite that passes because the tests are tautological (you're essentially testing that your function returns what you told it to return) gives you false confidence. I've seen this at agencies. Developers writing tests that always pass because nobody challenged what they were actually verifying.
Martin Fowler a bien écrit sur ce sujet — les pourcentages de couverture ne sont pas une mesure de la qualité des tests. Un chiffre de 90 % de couverture peut masquer une suite complètement creuse. — coverage percentages are not a measure of test quality. A 90% coverage number can mask a completely hollow suite.
Donc : ne testez pas tout. Ne testez pas parce que cela semble professionnel. Testez parce que vous avez identifié une logique critique et qu'il serait coûteux de la casser.
---
Ce Que Je Teste Maintenant (Et Ce Que Je Ne Teste Pas)
Voici la décision réelle à laquelle je suis arrivé après les huit ou neuf derniers mois :
Je teste :
- Toute fonction qui gère l'argent, les permissions ou la transformation de données
- Tout endpoint API qui n'est pas un simple pass-through CRUD
- La logique métier personnalisée où le client a spécifié le comportement exact par écrit
- Tout ce qu'une IA a écrit et que je n'ai pas entièrement lu ligne par ligne
Je ne teste pas :
- Rendu UI (Les snapshot tests ne m'ont jamais sauvé une fois en neuf ans. Pas une seule fois.)
- Wrappers d'API tiers où le comportement externe m'échappe
- Scripts ponctuels qui s'exécutent une fois puis sont supprimés
- Les hooks WordPress standard sauf s'ils font quelque chose d'inhabituel
C'est tout. Pas de grande philosophie. Juste une liste basée sur mes mauvaises expériences.
---
Le workflow qui fonctionne réellement pour moi
Puisque quelques personnes m'ont posé la question dans les communautés Slack où je suis, voici la séquence réelle :
- Écrire un bref commentaire de spécification en haut du fichier — ce que ce module fait, ce qu'il ne fait pas, les cas limites que je connais déjà.
- Demander à Cursor de générer des cas de test à partir de ce commentaire avant d'écrire une quelconque implémentation.
- Examinez ces cas de test. Supprimez les stupides. Ajoutez ceux que l'IA a manqués.
- Laissez Copilot ou Cursor écrire l'implémentation.
- Lancez les tests. Ils échoueront. Corrigez l'implémentation (pas les tests).
- Lisez le diff avant de pusher — le code assisté par l'IA a toujours besoin d'une relecture humaine.
L'étape 6 est non négociable. J'ai attrapé trois bugs véritablement graves au cours des quatre derniers mois juste en lisant le diff lentement avant de pusher. Rien de compliqué. Juste lire.
La formulation originale de Kent Beck sur le TDD n'a jamais porté sur 100% de couverture ou une méthodologie parfaite. Il s'agissait de construire une boucle de rétroaction assez rapide pour attraper les erreurs avant qu'elles ne s'aggravent. Cette idée — les boucles de rétroaction rapides — est plus pertinente maintenant qu'elle ne l'était en 2003. Parce que l'IA fait des erreurs plus vite que n'importe quel développeur que j'ai jamais engagé. was never about 100% coverage or perfect methodology. It was about building a feedback loop fast enough to catch mistakes before they compound. That idea — fast feedback loops — is more relevant now than it was in 2003. Because the AI makes mistakes faster than any developer I've ever hired.
---
FAQ
Est-ce que cela ralentit votre vitesse de livraison ?
D'environ 10 à 15 % sur les projets complexes. Sur les projets simples, peut-être pas du tout — l'IA génère les tests tellement rapidement que le surcoût est minimal. Pour les projets où un bug coûterait de l'argent réel à corriger après le lancement (et la plupart des projets qui rapportent de l'argent réel se qualifient), ces 15 % valent la peine cent fois.
Et TypeScript ? La typage fort ne remplace-t-il pas beaucoup de tests ?
Partiellement. TypeScript détecte toute une classe d'erreurs à la compilation que vous aviez l'habitude de tester. Mais les types ne testent pas la logique métier. Ils ne vérifient pas que votre fonction de calcul de remise applique les bonnes règles pour les clients en gros. C'est toujours à vous de le faire.
Les développeurs juniors doivent-ils utiliser des outils IA de codage s'ils n'écrivent pas de tests ?
Non. C'est mon opinion ferme. Un développeur junior utilisant Copilot sans tests, c'est essentiellement piloter un avion en pilote automatique sans comprendre comment fonctionne le pilote automatique ou comment atterrir manuellement. L'IA produira du code qui semble de niveau senior, le junior ne saura pas quelles parties méfier, et vous aurez un incident en production tôt ou tard. Les tests leur donnent au moins un mécanisme pour vérifier ce qu'ils acceptent.
Pourquoi avez-vous arrêté de faire des tests au départ, franchement ?
L'épuisement professionnel, en partie. Et une période où chaque projet était vraiment simple et les tests ne valaient vraiment pas la peine. L'erreur était de ne pas remarquer quand la complexité du projet changeait et s'adapter en conséquence. C'est la vraie leçon — pas « toujours tester » ou « ne jamais tester » mais savoir dans quelle catégorie un projet donné se situe.
---
Écrire des tests ne semblait pas être une protection. Ça semblait être de la paperasse. L'IA a changé ça. Pas parce que l'IA est mauvaise — elle m'a rendu significativement plus rapide — mais parce qu'elle a introduit une nouvelle classe d'erreurs confiantes, bien formatées, plausibles que je ne peux pas détecter en lisant le code comme je le faisais avant. Les tests ne sont pas pour l'IA. Ils sont pour moi. Un mécanisme de contrainte pour penser à ce que j'ai réellement besoin que le code fasse avant d'accepter ce que le modèle me remet.
J'aurais aimé l'encadrer de cette façon il y a deux ans.
