In our previous blog post, we have already introduced the topic of Microservices Consumer Driven Contract (CDC) Testing and the motivation behind it. We also took a look at PACT as a CDC testing framework by providing a getting started Spring boot based example. In the current blog post we will focus our attention on Spring Cloud Contract framework for CDC testing. The Spring Cloud Contract Project itself consists of three main components – Spring Cloud Contract Verifier, Spring Cloud Contract WireMock and Spring Cloud Contract RestDocs. Since this blogpost cannot cover all the possible combinations of technologies and options that Spring Cloud Contract provides, our major focus will be on the Spring Cloud Contract Verifier. However, just for curiousity, we have added two test samples – one for Spring WireMock and the other with Spring RestDocs in our demo project, just to get an idea. Further details, you can find on the official documentation.

Let’s get started from our Github project: Spring Clould Contract Demo Github Repo

Let’s first start by introducing our case. Suppose that we have two services (see Figure 1) – Consumer and Provider that communicate between each other via REST. The Provider or Product service in our case provides all product relevant information such as nametype and description, by a given product identification number. The Consumer, on the other hand, fetches the data and consumes the relevant information.
Consumer-Provider communication

When it comes to contract testing, we start by defining our first contract that contains the expectation of the API we are using. As a rule of thumb the contract has to be defined by the Consumer service, however in Spring Cloud Contract it is physically located in the Provider service code. One approach as advised in the official documentation is to clone the Provider service project and have it locally for writing the contract. The guide consists of two major steps that contain smaller steps. The first step focuses on what should be done on the Provider side and the second step groups the activities on the Consumer side.

Step 1 Actions Overview

1.1. Write the contract specification (Groovy DSL)
1.2. Generate automated acceptance tests on Provider side
1.3. Generate WireMock JSON stub & Publish the stub to Maven (local) repository

1.1. Write the contract specification (Groovy DSL)
The contract is written in Groovy DSL and consists of two main parts – defining the request and expected response. By specification, there is a minimum of elements that have to be defined. For the Request part those are: method and urlPath, for the response part: status code. Detailed information about the way they are defined as well as the Groovy DSL syntax specifics can be found here – https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_contract_dsl. In the following code block, you can see the defined contract for our Product demo case. The default location for specifying a contract is in /test/resources/contracts.

1.2. Generate automated acceptance tests on Provider side
When you are on the Provider side, you can use the possibilities of spring-cloud-contract-verifier to automatically generate a test based on this contract that verifies the Provider’s implementation. Before that you need to have a base class implemented that all of the generated tests will extend from. In our example this is the ContractVerifierBaseTest.java, which has to be configured in the build.gradle file (the full build.gradle example is available in the GitHub repository).

When you execute “gradle generateContractTests” from the provider project, the generated tests have to be located under /build/generated-test-sources. The following code block shows how exactly the test looks like. Its name is formed with the prefix validate_ + the name of the contract file (= validate_productContractDemo). Given that the ProductController request mapping is already implemented and you execute the test, it is expected to pass. However, as it is more likely the case, if you have not yet implemented the logic of your RestController, then the test will fail.

1.3. Generate WireMock JSON stub & Publish the stub to Maven (local) repository

Once the test passes and the Provider service-side necessary logic is implemented, we can move on to the next step – generating and installing stubs from the Provider. But before we do that on a technical level, let us have a look at why those stubs are necessary. On the consumer we do not want to execute our tests against a real deployed Provider service. On the other hand, we do not want to use an out of date mocked Provider service as already discussed in our previous blog post under Intergration tests. Therefore, Spring Cloud Contract provides us with the functionality to use a stubbed Provider for our Consumer tests, that is at the same time up to date with the real Provider. This is what we actually did in the step so far – we have created a contract, generated an automated test that is executed against the real Provider implementation. Once it is green, we can generate the Provider Stub and pass it on to the Consumer.

We do that by executing gradle clean build installThis command does two steps for us.

  • Firstly, it generates the WireMock (WireMock is a framework for service virtualization) JSON stub definitions (under /build/stubs/mappings).
  • Secondly, it publishes those stubs into the Maven local repository. The jar file contains the contract and the stub.

Consumer with stubbed Provider

Step 2 Actions Overview

1.1. Configure Stub Runner on the Consumer side
1.2. Execute the Consumer test – Stub Runner has embedded WireMock
1.3. Check verification results

1.1. Configure Stub Runner on the Consumer side
On the Consumer side, we have to write our test and make configurations to execute it against the Provider Stub. Ideally, we will have the tests written before creating the contract with the Provider. The ConsumerDemoTest.java does nothing more than executing the request for fetching Product data based on a product id. At the end it asserts that the received data is as expected. What is more interesting is this part of the configuration:

Using this line we make the configuration of spring-cloud-starter-contract-stub-runner. WorkOffline equals true, means that the stub runner will search for the Provider stub in the Maven local repository. With the value of ids, we say to use the latest installed stubs version from the Maven repo with groupId = info.novatec.spring.contract.cloud.example, artifcatId = provider-service and specify a port for the test. The Stub runner comes with an embedded WireMock, thus when starting your tests the Stub runner will start a WireMock server internally and install on it the Provider stubs.

1.2. Execute the Consumer test & check verification results
After that it will execute the test logic and finally will do the assertions. If everything has been properly set, the test is expected to pass. Below you can see a short info from the test execution log that proves the stub installation and running process. If an error has been found then of course the team working on Consumer service has to communicate with the Provider’s service team.

Summary

In this blog post we presented the second framework supporting the concept behind CDC – Spring Cloud Contract. It is only suitable for JVM based applications. PACT, on the other hand, provides a wider range of programming language support, which could be a factor when we have microservices and at least one of them is not Java based. Spring Cloud Contract is more platform-specific, but provides further functionalities such as the stub runner, and the automatic test generation on the Provider side. Whether it should be a first choice for Java, is a matter of project context, needs and personal choice.

An interesting consequence behind the idea of CDC is that it actually promotes the concept of Test Driven Development on the architectural level. You start by implementing a test on the consumer side that initially fails because there is no provider yet. Then you write/generate the contract with the Provider. The Provider, then, can generate tests out of this contract i.e. the requirements that it needs to fulfil. At first, the test will fail. After implementing the API logic, it will (hopefully) pass. At the end the consumer can also run the tests against the stubbed Provider and make them pass.

Leave a Comment

2 comments

  1. Hi Antoniya!

    This is a great post! Congrats 🙂 Glad that you enjoyed working with Spring Cloud Contract.

    > In this blog post we presented the second framework supporting the concept behind CDC – Spring Cloud Contract. It is only suitable for JVM based applications.

    Not necessarily. I’d say that it’s more suited for JVM based applications. When developing a non JVM basde application, if you’re the consumer, then you can run the Stub Runner Boot application – https://cloud.spring.io/spring-cloud-contract/spring-cloud-contract.html#_stub_runner_boot_application just by typing java -jar ... . That way you’ll automatically download the stubs and run them aside of your process.

  2. A

    Hi Marcin!

    Thank you for your feedback! I really found the framework great!

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close