Image de couverture : Au-delà du TDD : pourquoi vos tests unitaires ne garantissent pas l'intégrité architecturale
tech

Au-delà du TDD : pourquoi vos tests unitaires ne garantissent pas l'intégrité architecturale

03 June 2026
5 min de lecture
14 vues
Sébastien Muler

Le bug qui passe à travers tous vos filets

Imaginez : une PR de 14 lignes. Les tests passent. La code review est approuvée. Et pourtant, en production, les commandes clients se retrouvent corrompues. Deux jours d'incident pour une modification qui semblait anodine.

C'est exactement le scénario décrit dans un article récent sur DEV Community autour d'un outil appelé ArchMind. Un développeur refactorise OrderService, déplace un appel de méthode en dehors d'un DB::transaction(), et le système envoie des notifications email en plein milieu d'une écriture partielle. La moitié de la commande est persistée. L'autre non.

Le diff semblait inoffensif. Les types étaient corrects. La logique paraissait inchangée. Mais l'architecture d'exécution, elle, avait changé.

Ce cas illustre une limite fondamentale de nos pratiques de qualité actuelles — une limite que nous rencontrons régulièrement dans les projets PHP/Symfony de moyenne et grande envergure.


Ce que vos outils actuels ne voient pas

Dans une application moderne, une requête HTTP ne traverse pas un seul fichier. En Symfony comme en Laravel, un flux typique ressemble à ceci :

Route → EventListener → Firewall → Controller → Service → Repository → Event → Subscriber

Chaque couche a une responsabilité. Certaines décisions sont critiques : une transaction doit englober exactement les bonnes opérations, un événement doit se déclencher après — et seulement après — la persistance réussie des données.

Voici ce que font vos outils habituels :

  • PHPStan / Psalm → vérifient les types et la cohérence statique
  • Tests unitaires / PHPUnit → vérifient le comportement fonctionnel
  • Code review → examine les diffs ligne par ligne

Aucun de ces outils ne répond à cette question pourtant essentielle : le flux d'exécution de cette route a-t-il changé par rapport à ce qu'il était avant ?

Un test unitaire qui mocke la transaction ne détectera pas qu'elle a disparu. PHPStan ne sait pas que votre OrderService doit impérativement s'exécuter dans un contexte transactionnel. Et un reviewer humain peut passer à côté d'un appel déplacé de trois lignes dans un fichier de 400 lignes.


L'architecture comme artefact testable

L'idée défendue dans l'article source est élégante : les équipes frontend utilisent depuis longtemps le snapshot testing pour détecter les régressions visuelles. Si un composant UI change de manière inattendue, la CI échoue et le développeur doit valider consciemment ce changement.

Pourquoi ne pas appliquer le même principe à l'architecture d'exécution backend ?

Concrètement, cela signifierait capturer une représentation du flux d'une route — quels middlewares s'exécutent, dans quel ordre, quels services sont appelés, où se trouvent les frontières transactionnelles — et la comparer à une baseline versionnée.

# Snapshot : POST /orders (baseline)
authentication_middleware
tenant_middleware
DB::transaction [
  OrderService::create
  OrderCreated::dispatch
]

# Snapshot : POST /orders (après refactoring)
authentication_middleware
tenant_middleware
OrderService::create          ← ⚠ hors transaction
OrderCreated::dispatch        ← ⚠ hors transaction

La différence est immédiatement visible. La CI peut l'attraper. Le développeur doit explicitement approuver ce changement structurel — ou le corriger.

C'est la promesse d'ArchMind : rendre l'architecture vérifiable de façon automatisée, comme on le fait déjà pour les types et le comportement.


Ce que cela change pour vos projets Symfony

En pratique, cette approche invite à repenser ce que l'on considère comme un "changement risqué" dans une base de code.

Aujourd'hui, une PR qui déplace un appel de service dans un listener Doctrine, ou qui retire un @Transactional d'un service applicatif, peut passer toutes les validations automatisées sans déclencher la moindre alerte. Pourtant, ces changements peuvent avoir des effets en cascade sur la cohérence des données, l'ordre des effets de bord, ou la gestion des erreurs.

Quelques pistes concrètes pour aller dans ce sens, même sans outil dédié :

1. Documenter les flux critiques Pour vos routes métier sensibles (paiement, création de compte, traitement de commande), maintenez un diagramme de flux versionné dans votre dépôt. Un changement sur ce flux doit faire l'objet d'une mise à jour explicite et d'une validation.

2. Écrire des tests d'intégration structurels Au-delà de "est-ce que la commande est créée ?", testez "est-ce que la création se passe bien dans une transaction ?" avec des assertions sur le comportement transactionnel réel, pas mocké.

3. Utiliser les outils d'analyse d'architecture existants Des outils comme Deptrac permettent de définir des règles sur les dépendances entre couches et de les valider en CI. C'est une première forme de vérification architecturale automatisée.

4. Traiter l'ordre d'exécution comme une contrainte métier Si votre architecture impose qu'un événement se déclenche uniquement après commit, documentez-le comme une règle explicite — et envisagez de l'encoder dans un test.


Conclusion

Le TDD et les bonnes pratiques de test restent indispensables. Mais ils ont une limite claire : ils vérifient ce que fait le code, pas comment il s'articule. À mesure que les applications grandissent, cette distinction devient critique.

L'incident décrit dans cet article aurait pu arriver dans n'importe quel projet PHP/Symfony bien testé. Il ne s'agit pas d'un manque de rigueur individuelle, mais d'un angle mort collectif dans notre outillage.

Les approches comme ArchMind ouvrent une direction intéressante : faire de l'architecture un citoyen de première classe du pipeline de qualité, au même titre que les types et le comportement fonctionnel.

En attendant que ces outils mûrissent, la meilleure défense reste la discipline : documenter les invariants architecturaux, les versionner, et les revoir consciemment à chaque changement structurel.

📖 Cet article s'appuie sur Tests Verify Behavior. ArchMind Verifies Architecture. publié sur DEV Community.

Partager cet article