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 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:
Using the Pact DSL, the expected request and response are registered with the mock service.
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.
The consumer test code confirms that the response was correctly understood
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.
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.
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.
Pact useful links:
Pact JVM - pact support for Java
- FOLIO-1465Getting issue details... STATUS branch for this ticket is here