Sobes.tech
Middle+

Parlez des tests de contrat d'un microservice.

sobes.tech IA

Réponse de l'IA

Les tests de contrat se concentrent sur la vérification de l'interaction entre microservices au niveau de leur API (contrat). L'objectif est de s'assurer que le consommateur (service utilisant l'API) et le fournisseur (service fournissant l'API) respectent un "contrat" défini (schéma des requêtes/réponses, format des données, attentes).

Principes fondamentaux:

  • Consommateur-dirigé: Les tests sont basés sur les attentes du consommateur. Le consommateur détermine quelles données et formats il nécessite.
  • Tests bidirectionnels: Vérification à la fois de la capacité du consommateur (à travailler avec le contrat actuel) et du fournisseur (à respecter les attentes du consommateur).
  • Vitesse: Les tests s'exécutent rapidement, souvent dans un pipeline CI/CD, car ils ne nécessitent pas le déploiement de tous les services dépendants.

Le processus inclut généralement:

  1. Le consommateur crée des tests décrivant ses attentes pour l'API du fournisseur. Ces tests génèrent un "contrat".
  2. Le contrat est publié (par exemple, dans un dépôt centralisé).
  3. Le fournisseur utilise le contrat publié pour vérifier sa mise en œuvre de l'API. Il exécute des tests (généralement côté fournisseur), qui vérifient si son API respecte le contrat.
  4. En cas de divergence entre les attentes du consommateur et la mise en œuvre du fournisseur, le test échoue, indiquant une violation du contrat.

Outils:

  • Pact (le plus populaire)
  • Spring Cloud Contract
  • Swagger/OpenAPI avec outils de validation

Avantages:

  • Détection précoce des erreurs d'intégration: Les problèmes de compatibilité sont détectés avant le déploiement.
  • Réduction de la nécessité de tests d'intégration: Diminue la dépendance aux tests de bout en bout complexes et lents.
  • Tests indépendants: Permet de tester les services de manière indépendante.
  • Définition claire des attentes: Définit explicitement le contrat entre services.

Inconvénients:

  • Ne remplace pas complètement les tests d'intégration (vérifie uniquement l'interaction au niveau de l'API).
  • Requiert une discipline dans la gestion des versions des contrats.
  • Peut être plus complexe pour des services avec des contrats très complexes.

Exemple avec Pact:

  1. Le consommateur (par exemple, le service Order Service) utilise la bibliothèque Pact pour créer des tests côté consommateur.
    // Exemple de test consommateur avec Pact JVM
    @ExtendWith(PactConsumerTestExt.class)
    @PactTestFor(providerName = "ProductService", port = "8080")
    public class ProductServiceContractTest {
    
        @Pact(consumer = "OrderService")
        public RequestResponsePact createPact(PactDslWithRequest r) {
            return r.given("a product with id 1 exists")
                    .uponReceiving("a request for product by id")
                    .path("/products/1")
                    .method("GET")
                    .willRespondWith()
                    .status(200)
                    .headers(Map.of("Content-Type", "application/json"))
                    .body(new PactDslJsonBody()
                            .stringValue("id", "1")
                            .stringValue("name", "Laptop")
                            .numberType("price", 1200.00))
                    .toPact();
        }
    
        @Test
        void testGetProductById(MockServer mockServer) throws IOException {
            // Logique pour appeler l'API du fournisseur via mockServer
            // Vérifier que le consommateur gère correctement la réponse mockée
            HttpResponse response = Request.Get(mockServer.getUrl() + "/products/1").execute().returnResponse();
            assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
        }
    }
    
  2. Lors de l'exécution des tests côté consommateur, un fichier de contrat (.json) est généré.
  3. Ce fichier de contrat est publié dans un Pact Broker ou un autre dépôt centralisé.
  4. Le fournisseur (Product Service) utilise la bibliothèque Pact (par exemple, Pact Provider Verifier) pour vérifier sa mise en œuvre de l'API basée sur le contrat obtenu du Pact Broker.
    // Exemple de test fournisseur avec Pact Provider Verifier
    @Provider("ProductService")
    @PactFolder("relative/path/to/pacts") // ou utiliser Pact Broker
    public class ProductServiceVerificationTest {
    
        @TestTemplate
        @ExtendWith(PactVerificationInvocationContextProvider.class)
        public void verifyPact(PactVerificationContext context) {
            context.verifyInteraction();
        }
    
        @State("a product with id 1 exists")
        public void productWithId1Exists() {
            // Logique pour préparer l'état des données dans le service du fournisseur pour le test
        }
    
        // Ajouter l'URL du fournisseur où le service testé est en cours d'exécution
        @BeforeEach
        void beforeEach(PactVerificationContext context) {
            context.setTarget(new HttpTestTarget("localhost", 8080));
        }
    }
    
  5. Le vérificateur côté fournisseur appelle l'API réelle du fournisseur selon la spécification du contrat et compare la réponse obtenue avec celle attendue dans le contrat.

La vérification de contrat est une pratique importante pour assurer la fiabilité et la maintenabilité des systèmes basés sur des microservices.