A contract is an agreement between two or more parties. When you sign a contract, we are agreeing to a set of rights and/or obligations. A contract in a Contract Test is similar, it describes how an external service will behave so you know what to expect from it.

For each communication interface, there are usually two parties involved: the provider and the consumer. The provider serves data to consumers. The consumer processes data obtained from a provider.

In a REST world, a provider builds a REST API with all required endpoints; a consumer makes calls to this REST API to fetch data or trigger changes in the other service.

In an asynchronous, event-driven world, a provider (often also called a publisher) publishes data to a queue; a consumer (often called a subscriber) subscribes to these queues and reads (consumes) and processes data.

In other words, a " contract is less about testing your own microservice and more about specifying how you expect an external service to behave".

One of the main reasons that these contract tests can be useful is that they can be run against any stubs or mocks you are using that represent external services. This makes it easier and quicker to run.

Contract tests become very useful when used as part of consumer-driven contracts (CDCs). With CDCs, the consumer team ensures that these contract tests are shared with the provider team to allow the producer team to ensure that its microservice meets these expectations.

It is very important from a test feedback point of view, that these tests need to be run only against a single producer in isolation, so they can be faster and more reliable than the end-to-end tests they might replace.

In a way, contracts are as much about fostering clear lines of communication and collaboration, where needed, between microservices and the teams that consume them. It makes easier and more clear the lines of interaction between services. It is important to understand that CDCs requires good communication and trust between the consumer and producing service.

As the authors of the book Accelerate (Nicole Forsgren, Jez Humble, and, Gene Kim) said,

“The fear and anxiety that engineers and technical staff feel when they push code into production can tell us a lot about a team’s software delivery performance.”

So, besides the improvement of the communication between the consumer team and provider team. The contract tests reduce the fear and anxiety of the engineers that are working with both consumers and providers.

So with CDCs, we can identify a breaking change prior to our software going into production without having to use a potentially expensive end-to-end test.

Other benefits are that the tests run independently, give fast feedback, are stable, are easy to maintain, and give you the confidence to release.

Where do they sit in the test pyramid?

CDCs sit at the same level in the test pyramid as service tests, albeit with a very different focus. These tests are focused on how a consumer will use the service, and the trigger, if they break, is very different when compared with service tests.

If one of these CDCs breaks during a build of the Customer service, it becomes obvious which consumer would be impacted. So with CDCs, we can identify a breaking change prior to our software going into production without having to use a potentially expensive end-to-end test.

Sam Newnman on Building Microservices - Testing Pyramid

Sam Newnman on Building Microservices - Testing Pyramid

According to pactflow, these are the main values of contract tests:

  • They run fast because they don’t need to talk to multiple systems.
  • They are easier to maintain: you don’t need to understand the entire ecosystem to write your tests.
  • They are easy to debug and fix because the problem is only ever in the component you are testing - so you generally get a line number or a specific API endpoint that is failing.
  • They are repeatable.
  • Contract tests scale: because each component can be independently tested, build pipelines don’t increase linearly / exponentially in time
  • They uncover bugs locally, on developer machines: contract tests can and should run on developer machines prior to pushing code.

As we well know, the later in a project lifecycle that a bug is found, the costlier it is to fix. So using contract tests we bring the tests closer to the base of the pyramid. As it is very well illustrated in Beth’s image below that compares the contract test to the E2E.

From Beth’s excellent talk on the topic

From Beth’s excellent talk on the topic

Summary

So in summary, the contract tests bring more confidence and less anxiety for the whole team. It also helps in the documentation of the code and also helps the communication between teams. It is also cheaper and quicker than end-to-end tests. If you want to explore more about CDCs using Pact, check out Using Pact for Consumer-Driven Contract Testing

Happy testing!


References

This post would not be possible without the great texts that came before. I am only standing on the shoulder of giants.