Tests de contrat : détecter les promesses API brisées avant la production
Vous déployez une modification sur votre service utilisateur. Tous les tests passent. Le pipeline est vert. Cinq minutes plus tard, le service de notification commence à générer des erreurs en production. Les utilisateurs voient des écrans blancs. La cause racine ? Vous avez supprimé un champ de la réponse API que votre propre service n'utilisait jamais, mais dont dépendait le service de notification.
Les tests d'intégration n'ont pas détecté cela. Les deux équipes ont exécuté leurs propres tests, et tout était vert. Le problème n'est apparu que lorsque les services ont réellement communiqué entre eux en production. C'est le vide que comblent les tests de contrat.
Le vrai problème que les tests d'intégration manquent
Les tests d'intégration vérifient que les services peuvent se connecter et échanger des données. Mais ils ne garantissent pas que l'accord entre les services reste valide lorsqu'un côté change. Deux équipes peuvent avoir des tests d'intégration parfaitement verts indépendamment, et pourtant casser les systèmes de l'autre lors du prochain déploiement.
Pensez-y de cette façon : l'équipe A gère le service utilisateur. L'équipe B gère le service de notification qui consomme les données utilisateur. L'équipe A décide de nettoyer la réponse API en supprimant un champ qui semble inutilisé dans son propre code. Leurs tests d'intégration passent car ils testent leur propre service. Les tests d'intégration de l'équipe B passent aussi car ils testent contre un mock ou un instantané de l'ancienne API. Le contrat brisé ne se révèle que lorsque les deux services s'exécutent ensemble en préproduction ou en production.
Ce que font réellement les tests de contrat
Les tests de contrat rendent l'accord implicite entre services explicite et vérifiable. Chaque fois que deux services communiquent via une API, il existe un accord sur ce qui est envoyé et ce qui est reçu. Les tests de contrat transforment cet accord en vérifications automatisées.
Le concept fonctionne avec deux rôles :
Le diagramme de séquence suivant montre comment le fournisseur publie un contrat et le consommateur vérifie par rapport à celui-ci avant le déploiement :
- Fournisseur : Le service qui expose l'API
- Consommateur : Le service qui appelle l'API
Le fournisseur déclare ce qu'il garantit de délivrer. Le consommateur déclare ce dont il a réellement besoin. Tant que les deux parties sont d'accord, le test de contrat passe. Quand quelque chose change, le test échoue avant que la modification n'atteigne la production.
La plupart des équipes adoptent une approche pilotée par le consommateur. Le consommateur définit ses attentes dans un fichier de contrat. Le fournisseur vérifie ensuite si son API satisfait toujours tous les contrats de tous les consommateurs. Si une modification du fournisseur viole un contrat, l'équipe du fournisseur le sait immédiatement. Ils peuvent discuter avec l'équipe du consommateur, ajuster le changement, ou versionner l'API sans casser les consommateurs existants.
Pourquoi les tests de contrat sont plus rapides que les tests d'intégration
Le plus grand avantage pratique est la rapidité et l'indépendance. Les tests de contrat n'ont pas besoin d'exécuter d'autres services. Ils n'ont pas besoin d'une vraie base de données ou d'un environnement de préproduction complet. Vous exécutez simplement le fournisseur avec des données de test prédéfinies et vérifiez si la réponse correspond au contrat.
Un test de contrat se termine en quelques secondes. Un test d'intégration qui démarre plusieurs services et bases de données prend des minutes. Dans un pipeline CI, cette différence compte. Vous pouvez exécuter les tests de contrat tôt et échouer rapidement, sans attendre des suites d'intégration coûteuses.
Les tests de contrat aident également avec les dépendances externes que vous ne contrôlez pas. Si votre application appelle une API tierce, vous pouvez écrire un test de contrat qui vérifie si l'API externe renvoie toujours le format attendu. Quand le tiers modifie son API, votre test de contrat échoue et vous le savez avant que les utilisateurs ne soient affectés.
Ce que les tests de contrat ne couvrent pas
Les tests de contrat ne vérifient que le format et la structure. Ils vérifient que les bons champs existent avec les bons types. Ils ne vérifient pas si les données sont correctes d'un point de vue métier. Ils ne testent pas la stabilité du réseau, l'authentification en production, ou le temps de réponse sous charge.
Pour ces préoccupations, vous avez toujours besoin de tests d'intégration. Les tests de contrat et les tests d'intégration sont complémentaires, pas des remplacements. Les tests de contrat détectent les incompatibilités structurelles tôt. Les tests d'intégration détectent les problèmes d'exécution et de données plus tard.
Où placer les tests de contrat dans votre pipeline
Placez les tests de contrat après les tests unitaires et avant les tests d'intégration. Cet ordre a du sens car les tests de contrat sont plus rapides que les tests d'intégration mais offrent une confiance supplémentaire que les services que vous allez tester ensemble sont toujours compatibles. Si un test de contrat échoue, il est inutile de lancer des tests d'intégration coûteux qui échoueront probablement aussi.
Voici un ordre typique de pipeline :
- Tests unitaires
- Tests de contrat
- Tests d'intégration
- Tests de bout en bout (si nécessaire)
Par où commencer
N'essayez pas d'ajouter des tests de contrat à tous les services à la fois. Commencez par les services qui changent le plus souvent et qui causent le plus de problèmes lors de la communication avec d'autres services. Ce sont les points de friction où les équipes se cassent mutuellement fréquemment.
Recherchez ces signaux :
- Services où le changement d'une équipe casse fréquemment la fonctionnalité d'une autre équipe
- API dont dépendent plusieurs consommateurs
- Services qui modifient régulièrement leur format de réponse
- API externes qui ont changé de manière inattendue par le passé
Concentrez-vous d'abord sur ceux-ci. Une fois que les tests de contrat tournent et détectent de vrais problèmes, étendez-vous progressivement à d'autres services.
Liste de contrôle pratique avant d'ajouter des tests de contrat
- Identifiez les trois paires de services qui causent le plus de ruptures entre équipes
- Décidez d'utiliser des contrats pilotés par le consommateur ou par le fournisseur
- Choisissez un outil de test de contrat adapté à votre stack (Pact, Spring Cloud Contract, ou similaire)
- Commencez avec un fournisseur et un consommateur
- Exécutez les tests de contrat dans le CI avant les tests d'intégration
- Mettez en place un processus pour notifier les équipes lorsqu'un contrat est brisé
L'essentiel à retenir
Les tests de contrat détectent les incompatibilités API au moment où une modification est effectuée, pas après le déploiement. Ils s'exécutent rapidement, ne nécessitent pas d'environnement complet, et donnent aux équipes une alerte précoce avant que des promesses brisées n'atteignent la production. Commencez par les frontières de service les plus douloureuses, automatisez les contrats, et laissez le pipeline vous dire quand l'accord est rompu. Vos utilisateurs n'en sauront jamais rien, et c'est exactement le but.