Published on

What Is Contract Testing in Microservices Architecture

Authors
contract-testing

Introduction

Before going into the importance of contract testing in microservices applications, let's take a quick look at some important concepts.

Monolith Applications:

A monolithic application is a type of software architecture where all the application components and functionalities are tightly coupled together in a single codebase or executable. This means that the different parts of the software are not separated from one another and are all interdependent. Any changes or updates to the application require the entire application to be rebuilt and redeployed. In other words, if you want to make a small change to one part of the application, you have to rebuild and redeploy everything at once. This can be a time-consuming and complex process, especially for large applications.

Microservice Applications:

Microservice architecture is a software development approach that emphasizes building an application as a collection of small, independent services. These services are designed to perform a specific business function or task, and can be developed, deployed, and scaled independently of the other services. Each service runs in its own process and communicates with other services over a network, making it easier to change and update individual services without affecting the entire application.

Producer

In contract testing, the producer (sometimes called the provider) is the service that creates and exposes an API and defines the API contract.

Consumer

In the context of contract testing, the consumer refers to the party or system that uses the API exposed by the producer and tests their implementation of the API against the contract or specification provided by the producer.

Testing Monolith vs Microservice:

During testing, one advantage of a monolithic application is that it operates within a single process, allowing modules to communicate via local function calls instead of over a network. This means that unit and integration tests can verify module correctness, as any changes to the function calls between modules will likely result in a compilation error. As a result, it is difficult to break the communication contract between modules in a monolithic application.

Things can get complicated when it comes to microservices, as they need to communicate over the network to provide business functionalities. We cannot rely solely on the compiler, as the modules are independent and distributed. They are essentially two separate applications, each with its own testing and deployment pipelines, making testing a tricky job.

Testing in Microservices

When testing microservices, there are two options: deploying the set of services for integration testing or using mock objects. Both options have drawbacks. Deploying all services can be problematic because it is not always feasible. Mocking services can be unreliable because the tests are written separately from the actual code governing the function being tested, causing them to deviate from the desired behavior.

How can Contract Testing help?

In contract tests it's harder to deviate from the desired behavior as we have one shared definition of the contract between producer and consumer service. If the producer changes the response, it must be updated in the contract; otherwise, its tests will fail. Since the contract has changed, the consumer's tests must also be updated and will probably fail if the change is not backward compatible. This requires the teams to inform each other about the changes based on the contract.

Contract Testing Approaches

Usually, we use two different methods when creating contract tests.

Consumer-Driven Contract Testing (CDCT):

In this approach, the consumer of a service defines the contract or interface that it expects from the provider. The provider then implements the service to meet this contract, and the consumer tests the provider's implementation to ensure that it conforms to the contract. CDCT helps to ensure that changes to the provider do not break the consumer's expectations.

Usage:

Consumer-Driven Contract Testing (CDCT) is generally used when there are multiple consumers of a service or API, and each consumer has its own specific needs and expectations from the service. CDCT can help to ensure that changes to the provider do not break any of the consumers' expectations, and it allows consumers to take an active role in defining the contract.

Provider-Driven Contract Testing (PDCT):

In this approach, the provider of a service defines the contract or interface that it offers to its consumers. The provider then creates tests to verify that its service meets this contract. The consumers of the service can also run these tests to verify that their implementations conform to the contract. PDCT helps to ensure that changes to the consumer do not break the provider's expectations.

Usage:

Provider-Driven Contract Testing (PDCT) is generally used when there are multiple providers of a service or API, and each provider needs to ensure that its implementation conforms to a shared contract. PDCT can help to ensure that changes to the consumer do not break the provider's expectations, and it allows providers to take an active role in defining and verifying the contract.

Tools

There are several tools available to perform contract testing, but here are 2 popular ones along with brief explanations:

Pact:

This is a popular contract testing tool that allows teams to define and test contracts between different services. It supports multiple programming languages and offers features such as versioning, verification, and publishing of contracts.

Spring Cloud Contract:

This tool provides support for contract testing in Java applications using Spring Boot. It allows teams to define contracts and generate test cases automatically based on those contracts. It also integrates with popular testing frameworks such as JUnit.

Boost your testing skills with the latest methods and tools, keeping your code robust and ready for success, subscribe to the free newsletter today for updates and insights delivered straight to your inbox.