Pact overview

Pact is a contract testing tool. Contract testing is a way to ensure that services (such as an API provider and a client) can communicate with each other. Without contract testing, the only way to know that services can communicate is by using expensive and brittle integration tests.

Contract testing is immediately applicable anywhere where you have two services that need to communicate - such as an API client and a web front-end. Although a single client and a single service is a common use case, contract testing really shines in an environment with many services (as is common for a microservice architecture). Having well-formed contract tests makes it easy for developers to avoid version hell. Contract testing is the killer app for microservice development and deployment.

Pact is a consumer-driven contract testing tool. This means the contract is written as part of the consumer tests. A major advantage of this pattern is that only parts of the communication that are actually used by the consumer(s) get tested. This in turn means that any provider behaviour not used by current consumers is free to change without breaking tests.

Consumer testing

Consumer Pact tests operate on each interaction described earlier to say “assuming the provider returns the expected response for this request, does the consumer code correctly generate the request and handle the expected response?”.

Each interaction is tested using the pact framework, driven by the unit test framework inside the consumer codebase:

  1. Using the Pact DSL, the expected request and response are registered with the mock service.

  2. The consumer test code fires a real request to a mock provider (created by the Pact framework).

  3. The mock provider compares the actual request with the expected request, and emits the expected response if the comparison is successful.

  4. The consumer test code confirms that the response was correctly understood

Provider testing

In contrast to the consumer tests, provider verification is entirely driven by the Pact framework. In provider verification, each request is sent to the provider, and the actual response it generates is compared with the minimal expected response described in the consumer test. Provider verification passes if each request generates a response that contains at least the data described in the minimal expected response.

Using a Pact Broker

Using file system for sharing pacts from the consumer with the provider is not very manageable when there are multiple teams contributing to the code base, and pushing to CI. Pact Broker can be used to do this instead. Using a broker simplies the management of pacts and adds a number of useful features, including some safety enhancements for continuous delivery. Here is more documentation about Pact Broker.

Example

There is a good talk which describes the real benefit of this approach.

pact-workshop-js is a good example of contract testing. It uses simple consumer with one API call on the client to provider which is written in Node.js.

Client flow:

Pact solves the case when the provider is mocked on consumer based on assumptions how the provider works at the given point in time. Over time the provider changes and its mocks on consumer side becomes stale which is why these tests are unreliable. As a result a Pact layer acts as intermediator between consumer and provider. In this situation the consumer test code fires a real request to a mock provider (created by the Pact framework). The mock provider compares the actual request with the expected request, and emits the expected response if the comparison is successful. After that consumer test code confirms that the response was correctly understood.

Provider flow:

Pact useful links:

Official site

Pact JS - pact support for Javascript

Pact JVM - pact support for Java

pact-workshop-js

Atlassian YouTube video about PACT 

POC for contract testing with Okapi backend (Consumer)

POC for contract testing with Okapi backend (Provider)

FOLIO slack #automated-testing-channel


JIRA Tickets:

Epic:   FOLIO-1477 - Getting issue details... STATUS

FOLIO-1458 - Getting issue details... STATUS

FOLIO-1461 - Getting issue details... STATUS  

FOLIO-1465 - Getting issue details... STATUS  branch for this ticket is here