22. Tester les contrats : protéger les frontières réelles
Pourquoi ce chapitre existe
Les tests internes peuvent tous passer alors qu'un consommateur ne comprend plus une API, qu'un événement ne peut plus être désérialisé ou qu'une erreur a changé de statut. Les frontières entre composants sont des lieux où les suppositions se multiplient. Les tests de contrat réduisent ce risque en vérifiant, de façon automatique, l'engagement partagé plutôt que deux implémentations séparées.
Les idées essentielles
- Un test de contrat vérifie une promesse entre producteur et consommateur, pas simplement un format JSON.
- Il doit couvrir les scénarios qui motivent l'intégration : succès, erreurs, valeurs inconnues, versions et propriétés temporelles pertinentes.
- Les contrats appartiennent aux frontières et à leurs responsables ; un outil ne crée pas cette responsabilité.
- Un contrat trop large reproduit l'intégration entière ; un contrat trop faible laisse passer les ruptures importantes.
Concevoir un contrat testable
Le consommateur formule ce dont il a réellement besoin : « quand une réservation expire, je reçois son identifiant, sa version et une raison stable ». Le producteur vérifie qu'il peut satisfaire cette attente sans exposer des détails inutiles. Les deux parties discutent les zones d'incertitude — ordonnancement, doublons, codes d'erreur, champs optionnels — avant qu'elles ne deviennent des incidents.
Les événements méritent une attention particulière. Leur livraison est souvent au moins une fois ; le consommateur doit donc être capable de tolérer le doublon ou le producteur doit fournir une sémantique différente. L'ordre et le délai doivent être testés ou explicitement laissés sans garantie, jamais supposés en silence.
Un consommateur peut exiger une réponse ou un événement précis. Il ne doit pas dicter les tables, classes, requêtes ou outils internes du producteur. Le contrat protège le comportement partagé et laisse chacun libre de changer ce qui n'est pas observable.
Anti-patterns
Générer un schéma sans exemples de comportement
Un schéma détecte une propriété absente ; il n'explique pas toujours ce que signifie une valeur, une erreur ou une séquence. Ajouter des exemples exécutables aux scénarios sensibles transforme une structure en engagement réellement utile.
Laisser les consommateurs inconnus hors de la transition
Une interface publique ou un export peut avoir des usages non déclarés. Avant une rupture, mesurer les clients, annoncer la dépréciation et prévoir une période de compatibilité est souvent plus sûr qu'un test bilatéral avec les seuls consommateurs connus.
Dupliquer les tests de bout en bout sous un autre nom
Le contrat doit rester ciblé et stable. S'il dépend de toute l'infrastructure ou de toutes les règles métier, il perd sa vitesse et son diagnostic ; il n'est plus une protection de frontière.
Bonnes pratiques
Versionner le comportement de transition
Lors d'une évolution, garder le contrat ancien et nouveau aussi longtemps que les deux peuvent coexister, puis mesurer l'usage avant de supprimer. Le test de contrat devient ainsi un garde-fou de déploiement progressif, pas seulement un contrôle de CI.
Faire remonter les contrats dans la revue de changement
Une modification d'API ou d'événement devrait rendre visible son contrat, ses consommateurs, son plan de compatibilité et son observabilité. Cette pratique est souvent plus efficace qu'une validation tardive par une équipe d'intégration séparée.
Checklist — Une frontière est-elle réellement protégée ?
- Quel consommateur et quel comportement le contrat sert-il ?
- Les succès, erreurs, valeurs inconnues et compatibilités importantes sont-ils couverts ?
- Les délais, doublons et ordres attendus sont-ils définis ou explicitement non garantis ?
- Qui possède l'évolution et la dépréciation du contrat ?
- La CI détecte-t-elle la rupture avant le déploiement ?
- Comment l'usage réel et les échecs de la frontière seront-ils observés ?
À retenir
Les tests de contrat rendent les frontières visibles et négociables. Ils réduisent les régressions d'intégration lorsqu'ils protègent une promesse de comportement précise, tout en laissant chaque partie évoluer derrière cette promesse.