Pact Contract Testing

Contract testing is a technique used to ensure that different systems or components of a system can communicate with each other as expected. One popular tool for contract testing is Pact.

With Pact, you can write tests that describe the expected interactions between your service (APIs or microservices etc.) and its dependencies, and then use those tests to ensure that the actual interactions match the expected interactions.

Consumer and Provider testing

In the context of Pact contract testing, the terms Consumer and Provider refer to two different components in a software system that communicate with each other.

A consumer is typically the client or customer of an API or service that requests data or functionality from a provider, which is the server or backend that responds to those requests and provides the necessary data or functionality.

The consumer is responsible for defining the expectations of the API or service that it is consuming. This includes defining the requests that it will make to the provider and the expected responses that it should receive. The consumer then generates a contract, which is a JSON file that defines these expectations.

Here's an example of a simple consumer pact test written in JavaScript:

import { Pact } from '@pact-foundation/pact';
import { expect } from 'chai'
import axios from 'axios'

describe('My API', () => {
  let provider;

  before(() => {
    provider = new Pact({
      consumer: 'My Consumer',
      provider: 'My Provider',
      port: 1234,
    });
  });

  describe('when a GET request is made to /items', () => {
    before(() => {
      provider.addInteraction({
        uponReceiving: 'a request for all items',
        withRequest: {
          method: 'GET',
          path: '/api/v1/items',
        },
        willRespondWith: {
          status: 200,
          body: {
            items: [
              { id: 1, name: 'Item 1' },
              { id: 2, name: 'Item 2' },
            ],
          },
        },
      });
    });

    it('returns a list of items', async () => {
      const response = await axios.get('http://localhost:1234/api/v1/items');
      expect(response.status).to.equal(200);
      expect(response.data).to.deep.equal({
        items: [
          { id: 1, name: 'Item 1' },
          { id: 2, name: 'Item 2' },
        ],
      });
    });
  });
});

This test describes an interaction between a consumer (My Consumer) and a provider (My Provider) where the consumer makes a GET request to the endpoint /api/v1/items and expects to receive a JSON object containing an array of items.

When you run this test, it will start the mock service on port 1234 and the test will request that endpoint, if the response matches the expected one and it will generate the contract.

The Provider, on the other hand, is responsible for verifying that it can meet the expectations defined by the consumer contract. The provider reads the contract generated by the consumer and uses it to generate tests that will verify that the API or service behaves as expected.

In the CI/CD pipeline consumer contract and provider verification will run to check its possible to deploy the following contracts and the provider will communicate with the pact broker central repository to manage pact contracts.

Pact Broker

Pact Broker is a tool or service that is used in conjunction with Pact contract testing. It is a web application that acts as a central repository for storing and managing contracts between consumers and providers.

When a consumer generates a contract, it can publish the contract to the Pact Broker. The provider can then retrieve the contract from the Pact Broker and use it to verify that it can meet the expectations defined by the consumer.

The following example is a publish the contract to a pact broker. if you are using the Pact-JS library for Node.js, you can publish the contract to the Pact Broker using the following command:

pact-broker publish ./path/to/pact/file --broker-base-url=https://your.pact.broker.url --consumer-app-version=1.0.0

The Pact contract file is located at ./path/to/pact/file which is generated by the consumer test.

Run Pact Verification in CI/CD

Deploy Pact tests as part of your continuous integration and delivery (CI/CD) pipeline. There are a few ways to do this depending on your setup, but generally, the process involves:

  1. Run the Pact tests as part of your CI pipeline, using a tool like Jenkins, Travis CI, or CircleCI.

  2. Publish the Pact contracts to a Pact Broker (check for pact broker section above). The Pact Broker is a central repository for storing the contracts between consumers and providers.

  3. Verify the provider's implementation against the published contracts. This can be done automatically as part of your CD pipeline, or manually by developers. Here's an example of how you might set up your CI pipeline to run Pact tests and publish the contracts to a Pact Broker:

# .travis.yml (for Travis CI)

language: node_js

node_js:
  - 14

before_script:
  - npm install -g @pact-foundation/pact-cli

script:
  - npm test
  - pact-verifier --provider-base-url=http://localhost:1234 --pact-url=http://localhost:9292/pacts/provider/My%20Provider/consumer/My%20Consumer/latest

after_success:
  - pact-broker publish --consumer-version=1.0.0 --pact-url=./pacts/my_consumer-my_provider.json --broker-base-url=http://localhost:9292

This script will run the tests, publish the contracts to the broker if the tests passed, and also you can use the pact-verifier command to check if the provider is compatible with the contracts, you can add it to your pipeline as well.

You can also set up your pipeline to automatically verify the provider's implementation against the published contracts. This can be done using the pact-provider-verifier command.

Keep in mind that you will need to have a pact broker running to be able to publish the contracts and also to verify them.

It's also worth noting that Pact supports several different languages, platforms, and CI/CD tools, so the exact steps for setting up your pipeline will depend on the technologies you're using.

Pactflow

Pact Provider as a service (SaaS) through Pactflow, which is a hosted version of the Pact Broker. Pactflow provides additional features on top of the standard Pact Broker, including:

  • Automated provider verification

  • Webhooks and integrations with other tools

  • Advanced pact management and searching

  • Role-based access control (RBAC)

  • Customizable branding

  • And more

Pactflow allows you to easily manage and verify your pacts in a cloud-based environment. You can use it to automate the process of verifying your provider's implementation against the contracts. It also provides a web interface for browsing and managing your contracts and verifying them, and it can be integrated with popular CI/CD tools like Jenkins, Travis CI, and CircleCI.

To use Pactflow, you need to sign up for an account and create a new "workspace" for your project. Once you've created your workspace, you can configure your CI pipeline to publish the contracts to Pactflow, and set up automated provider verification.

You can also use the Pactflow API to interact with your contracts and perform various tasks like triggering verification, retrieving the results, etc. Overall, Pactflow provides a powerful and easy-to-use platform for managing your Pact contracts and ensuring that your services are compatible with each other.

References