Contract Tests

This guide provides a brief overview of the field of Contract Testing

Contract Tests

This guide wants to provide a basic overview over what Contract Testing is and why it is useful for the development and testing of player microservices. If you want to further study this topic, please take a look at the stated sources.

What is contract testing?

Contract testing is a software testing concept used in the field of microservices and distributed systems, to ensure that the interactions between different services or components, of that distributed system, conform to the agreed upon contracts or specifications. In these contracts is defined the expected input and output of the respective services, defining their behaviour and thus helping to maintain compatibility and prevent regressions when making changes or updates.

What is the benefit of contract testing?

When trying to test the interaction between different microservices in a distributed system, usually an entire test environment has to be set up and all the involved microservices have to be deployed to it, essentially performing a slow and costly end-to-end test.

The problem is, when intending an interface test, the deployment of all the involved microservices is not necessary, as only a small part of the other services, their input/output, is needed, and the full deployment therefore, only increases the complexity and resource consumption of the test itself. In addition, the lack of isolation makes identifying the cause of a failed test much harder than in an isolated integration test.

The purpose of contract testing is to lower the level of such a test from the end-to-end level, to the level of an integration test, making the deployment of other services unnecessary and thereby reducing the complexity and increasing the isolation of the test.

How does contract testing work?

The concept of contract testing mandates that the interaction between distributed systems be defined in a contract. This contract can then be used, as input, to generate a fitting mock service for the microservice in question. This concept is further described in the following illustration:

Contract Testing simplified

The contract contains the defined interactions between the two microservices consumer and provider. In this system, the provider microservice is responsible for producing an output, which the consumer microservice consumes as input. Their interaction is being defined in the contract. Based on this contract, mocks can then be generated. A mock provider for the consumer, that mocks the output to be consumed, and a mock consumer for the provider, that mocks the consumption of the output. This way, the interaction between both the consumer and the provider service can now be tested without having to deploy the other service.

Both services can now create their respective test classes and then test their interaction against the generated mock services. This offers much more flexibility, durability and isolation, focusing only on a single aspect of the interaction per test and not having to test ‘basically everything’ all at once in an end-to-end test.

Sources

Relevant sources:

Last modified February 4, 2025: fix go & npm dependencies (8ff1fa0)