Sobes.tech
Middle+

Parla dei test di contratto di un microservizio.

sobes.tech AI

Risposta dell'AI

I test di contratto si concentrano sulla verifica dell'interazione tra microservizi a livello di API (contratto). L'obiettivo è assicurarsi che il consumatore (servizio che utilizza l'API) e il fornitore (servizio che fornisce l'API) rispettino un "contratto" definito (schema delle richieste/risposte, formato dei dati, aspettative).

Principi fondamentali:

  • Orientato al consumatore: I test si basano sulle aspettative del consumatore. Il consumatore determina quali dati e formati sono necessari.
  • Test bidirezionali: Si verifica sia la capacità del consumatore (di lavorare con il contratto attuale) sia quella del fornitore (di rispettare le aspettative del consumatore).
  • Velocità: I test vengono eseguiti rapidamente, spesso in una pipeline CI/CD, poiché non richiedono il deployment di tutti i servizi dipendenti.

Il processo generalmente include:

  1. Il consumatore crea test che descrivono le sue aspettative sull'API del fornitore. Questi test generano un "contratto".
  2. Il contratto viene pubblicato (ad esempio, in un repository centralizzato).
  3. Il fornitore utilizza il contratto pubblicato per verificare la propria implementazione dell'API. Esegue i test (solitamente lato fornitore), che verificano se la sua API è conforme al contratto.
  4. In caso di discrepanze tra le aspettative del consumatore e l'implementazione del fornitore, il test fallisce, indicando una violazione del contratto.

Strumenti:

  • Pact (il più popolare)
  • Spring Cloud Contract
  • Swagger/OpenAPI con strumenti di validazione

Vantaggi:

  • Rilevamento precoce degli errori di integrazione: I problemi di compatibilità vengono rilevati prima del deployment.
  • Riduzione della necessità di test di integrazione: Diminuisce la dipendenza da test end-to-end complessi e lenti.
  • Test indipendenti: Permette di testare i servizi in modo indipendente.
  • Definizione chiara delle aspettative: Definisce esplicitamente il contratto tra i servizi.

Svantaggi:

  • Non sostituisce completamente i test di integrazione (verifica solo l'interazione a livello di API).
  • Richiede disciplina nella gestione delle versioni dei contratti.
  • Può essere più complesso per servizi con contratti molto complessi.

Esempio di utilizzo con Pact:

  1. Il consumatore (ad esempio, il servizio Order Service) utilizza la libreria Pact per creare test del lato consumatore.
    // Esempio di test del consumatore con 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 {
            // Logica chiamata API fornitore tramite mockServer
            // Verifica che il consumatore gestisca correttamente la risposta mockata
            HttpResponse response = Request.Get(mockServer.getUrl() + "/products/1").execute().returnResponse();
            assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
        }
    }
    
  2. Durante l'esecuzione dei test del lato consumatore, viene generato un file di contratto (.json).
  3. Questo file di contratto viene pubblicato in un Pact Broker o in un altro repository centralizzato.
  4. Il fornitore (Product Service) utilizza la libreria Pact (ad esempio, Pact Provider Verifier) per verificare la propria implementazione API basata sul contratto ottenuto da Pact Broker.
    // Esempio di test del fornitore con Pact Provider Verifier
    @Provider("ProductService")
    @PactFolder("relative/path/to/pacts") // o usare 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() {
            // Logica di preparazione dello stato dei dati nel servizio fornitore per il test
        }
    
        // Aggiungi l'URL del provider dove il servizio in test è in esecuzione
        @BeforeEach
        void beforeEach(PactVerificationContext context) {
            context.setTarget(new HttpTestTarget("localhost", 8080));
        }
    }
    
  5. Il verificatore lato fornitore chiama l'API reale del fornitore secondo la specifica del contratto e confronta la risposta ottenuta con quella attesa nel contratto.

Il test di contratto è una pratica importante per garantire l'affidabilità e la manutenibilità dei sistemi basati su microservizi.