Search code examples
node.jspactpact-broker

pact.io: Select specific endpoints for provider test


We are running a microservice architecture and want to set up contract testing in our project. Our consumers do not know which request is handled by which microservice. We want our microservices to select the interactions from the pacts that they should participate in.

Example:

  • Consumer A writes a test which is testing POST /users.
  • Consumer A writes a second test for POST /users with different parameters.
  • Consumer A writes a test for GET /users/$userId.
  • Consumer A writes a test for GET /articles/$articleId.
  • Microservice A handles all POST /users requests.
  • Microservice B handles all GET /users/$userId requests.
  • Microservice C handles all GET /articles/$articleId requests.
  • All of the consumer tests only have a single request in their interactions.

We want to put provider tests next to the Microservices. Each microservice should only test the endpoints that it is capable of handling. In this scenario, Microservice A would test all of the POST /users contracts. Microservice B would select the GET /users/$userId contracts and so on.

Is there a way to do so with pactflow.io and nodejs bindings for pact?

Edit: Added the architecture diagram: Architecture Diagram


Solution

  • We have found a solution to our particular problem:

    • The consumer does not know which service acts as a provider, but it knows the (HTTP method, URL) tuple that it calls.
    • The microservice knows every (HTTP method, URL) that it is responsible for.

    We define a provider as the tuple (HTTP method, URL). As a result, a consumer contains many tests for many providers and a microservice also contains many tests for many providers.

    Something like this in node.js for the consumer:

    const consumer = "MyConsumer";
    
    const providerGetArticles = new Pact({ consumer, provider: 'GET-articles', ...  });
    
    const providerGetArticlesArticleId = new Pact({ consumer, provider: 'GET-articles-:articleId', ...  });
    
    const providerPostUsers = new Pact({ consumer, provider: 'POST-users', ...  });
    
    const providerGetUsers = new Pact({ consumer, provider: 'GET-users', ...  });
    
    const providerGetUsersUserId = new Pact({ consumer, provider: 'GET-users-:userId', ...  });
    
    providerGetArticles.setup().then(() => {
      providerGetArticles.addInteraction(
        {
          withRequest: { method: 'GET', path: '/articles' },
          ...
    
    
    providerGetArticlesArticleId.setup().then(() => {
      providerGetArticlesArticleId.addInteraction(
        {
          withRequest: { method: 'GET', path: '/articles/12345' },
          ...
    
    providerPostUsers.setup().then(() => {
      providerPostUsers.addInteraction(
        {
          withRequest: { method: 'POST', path: '/users' },
          ...
    

    And like this for a microservice that handles GET /articles and GET /articles/:articleId

    new Verifier({ provider: 'GET-articles', ... }).verifyProvider()...
    
    new Verifier({ provider: 'GET-articles-:articleId', ... }).verifyProvider()...
    

    We can now start the single microservice in isolation and run the provider tests.