Improve the design and testing of your micro-services through Consumer-Driven Contract Tests (1/3)
In a micro-services world, testing the successful integration between services is critical for ensuring that the services won’t fail in production just because they’re not speaking the same language.
Why should you read this article ?
If you develop or maintain micro-services you already asked yourself those questions :
How do we deal with testing? How do we confirm all services are working well together ?
CDC is an answer to those questions.
Let’s discover what is behind, let’s go to the upside-down !!!
Before deep diving into CDC let’s review how do we test integration between client and services at the moment.
How can we test this simple integration ?
We can use a mock of the API to design our client integrations. With mocks, we do not need to set up a whole runtime environment. We can run isolated tests between the client and a mock of the API.
Limits of mocking
- What happens if there is a change in the real producer ?
The system could perfectly run on a “test” environment could not be integrated in the real world.
- The owner of the mock is the consumer
As a consumer I can not be sure that the API has not been changed by the API’s provider, so I am not able to adapt the mock accordingly.
- Not trustworthy
How can we be sure that the mocks are valid ?
End to end testing
To test interfaces between a client and an API the most used technique is end-to-end testing. In end-to-end tests (E2E tests), real servers or containers are set up so that client and provider are available in a production-like runtime environment.
To execute integration tests, the client is usually triggered by providing certain input in the user interface. The consumer then calls the provider and the test asserts if the results meet the expectations defined in the contract.
Limits of E2E testing
The feedback loop of E2E testing is really long (setup takes a while and the tests run as well).
- All services need to be up before running the tests
This kind of tests requires a clean/dedicated integration environment. It’s really hard to get one in a lot of organizations at the moment.
Consumer-Driven Contract approach as an alternative
If we take a look at the definition of an integration test : “An integration test is a test between an API provider and an API consumer that asserts that the provider returns expected responses for a set of pre-defined requests by the consumer. The set of pre-defined requests and expected responses is called a contract.”
This is the main focus of the approach : CONTRACTS.
The whole idea behind CDC is to involve consumers of the future API in the creation of the API itself. API changes will be driven by consumers.
- Producer : Service that exposes an API.
- Consumer : Service that consumes the API of the producer.
- Contract : Agreement between producer and consumer on how the API will look like.
- Consumer Driven Contracts : Approach where the consumer drives the changes of the API of the producer.
How does it work ?
- Define API contract on the consumer side.
Write Unit tests that define clearly what are the interactions and behaviors expected from the provider.
- Enforce the contract on the service provider side.
Unit tests on the provider side ensure that the provider implementation respect the expectations (contract) defined by the consumer.
Benefits of CDC
CDC makes your life easier :
- Make integrating and testing a service in a microservice world easier
- Drive the providers implementation through the contract
Start by enforcing the contract without the API, then design the API accordingly : you will write less code and avoid extra features.
- Help providers make changes without being scared of accidentally breaking their consumers
- Let consumer know that the APIs they consume won’t suddenly break
- Allows consumers to develop against API definitions before the provider API has actually been developed : Design first approach