Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ


Choose your language

InfoQ Homepage News Q&A with Marcin Grzejszczak on Spring Cloud Contract

Q&A with Marcin Grzejszczak on Spring Cloud Contract

This item in japanese

Marcin Grzejszczak is a software engineer at Pivotal. He contributes to various open source projects and is also the author of the Mockito Cookbook. Currently, he is working on Spring Cloud Contract, a consumer-driven contracts framework for Java. InfoQ has interviewed Grzejszczak in order to discuss some of the framework's benefits, and how in particular consumer-driven contracts can help with microservice testing.

Key Takeaways:

  • Consumer-driven contracts are like test-driven developments for architecture
  • Spring Cloud Contract integrates well with the Spring ecosystem
  • End-to-end testing can become redundant when using consumer-driven contracts
  • Spring Rest Docs can be used as an alternative to the Groovy DSL within Spring Cloud Contract
  • In the future, Spring Cloud Contract will provide improved tooling for non-Java users

InfoQ: Could you give an overview of the consumer-driven contracts pattern, and explain what sorts of problems it solves in microservices development?

Marcin Grzejszczak: Consumer-driven contracts is a process that aims to help users test their software and create a better architectural design. We can call it test-driven development progressed to the level of architecture. Today’s software requires a very fast reaction to customer demands, legislation changes, business requirements, etc. On the other hand, we, as an IT industry, want to deliver as fast as possible reliable software that has been tested and doesn’t contain bugs. That’s why we create deployment pipelines - to automate that release and testing process. With microservices, the problem is amplified due to the nature of the architecture style. We can't break monoliths into microservices without impacting our test processes.

The complexity that was contained within a monolithic structure gets pushed to the architectural level. Consumer-driven contracts tries to define some clear boundaries of communication between teams. The overall flow of CDC is such that the consumers define their expectations of what the API / messages should look like. Those expectations are called contracts. From those contracts stubs are generated that can be later reused by the consumer teams during their building process. The contract needs to be also validated on the producer side. That leads to an introduction of a fail-fast approach to your tests on both the producer and the consumer side. By fail-fast, we mean failing to build the software vs finding out by debugging production (e.g. we have made a typo in our REST / AMQP message).

Consumer-driven contracts shift API design towards those who use it. Typically the serverside team just announces what the API will look like. Often, due to the number of consumers, that’s the only possible way. But that’s not always the case. I’ve seen companies where the API wasn’t exposed to the public and teams didn’t want to cooperate on what the API should look like. CDC tries to change that approach to the one where it’s the consumer who drives the change of the API. Come to think of it, it really makes sense. It’s not the server side team that consumes the API. The consumer does it; that’s why the created API should suit the consumer as much as possible.

InfoQ: What is the motivation for Spring Cloud Contract, and why would you use it instead of an alternative consumer-driven contracts framework?

Grzejszczak: Together with Jakub Kubrynski from Devskiller company, we’ve made an analysis of the CDC frameworks. We came to the conclusions that they had a high learning curve and were very verbose. This is how Accurest, the predecessor of Spring Cloud Contract, was born in December 2014. We’ve decided to introduce a statically typed Groovy DSL to define contracts. And here comes the main difference between Spring Cloud Contract and other CDC frameworks. From the contract, Spring Cloud Contract generates not only stubs but also tests. That means that the developer needs only to define a contract and the rest will get automatically generated for the producer. That was a very important decision that we wanted to make, since the very essence of CDC is that the generated stubs are assumed to be trusted. If in the contract one defines that an endpoint `/foo` exists and you can access it via a GET method, then we generate a test on the producer side by sending a GET request to a `/foo` endpoint. If there is no such endpoint, then the test is broken and no stubs will be generated.

Spring Cloud Contract obviously integrates very well with Spring environment. We have support for messaging using Spring Integration, Spring Cloud Stream, Spring AMQP and Apache Camel. But what makes Spring Cloud Contract an attractive option is a component called Stub Runner. I’ve mentioned that stubs are generated from contracts. By default we expect the users to publish the producer stubs and contracts in the form of a JAR file to a Maven repository. Let’s assume that the stub has a group id "org.springframework" and artifact id "spring-boot-application". To run the stubs, the consumer can have its tests annotated as follows: @AutoConfigureStubRunner (ids={'org.springframework:spring-boot-application:+'}

What happens is that the framework will automatically download the latest version of the "org.springframework:spring-boot-application" JAR with stubs, and then start an in-memory HTTP server fed with stubs on a random port. This means that with one annotation you can stub your whole environment for your build! What is also really interesting is that Spring Cloud Contract can completely stub out your service discovery tool. That means that the stubs are registered in an in-memory version of a service registry. That way you can send a real HTTP request to a real HTTP server as if you used service discovery.

If you’d want to perform some smoke tests of your packaged application in a test environment, Spring Cloud Contract’s Stub Runner can also be very handy. The downloaded stubs can be registered in a real service discovery tool (e.g. Eureka), and real messages defined in contracts can be sent to real queues (e.g. RabbitMQ). That way your application won’t even know that it’s talking to stubs.

InfoQ: What impact, if any, does the consumer-driven contracts pattern have on end-to-end testing?

Grzejszczak: That’s a very good question. Like I mentioned, using microservices increases the complexity of testing and deploying applications. In particular, the combination of deployment and end-to-end testing is interesting. Let’s assume that our system consists of 50 microservices and let’s try to ask a couple of questions:

  1. Should every team have its deployment environment for every microservice that gets built?
  2. Who will pay for those 50 environments?
  3. If we decide not to have an environment per microservice, how will we deal with deployment queues? If end-to-end tests take a long time to run we will have to wait a long time for our turn...
  4. Should those environments consist of 49 other microservices deployed in production versions or development versions? Or maybe the tests should be executed for both production and development versions?
  5. Who will set up those environments and who will maintain them?
  6. Sometimes companies can’t have production data in test environments - who will obfuscate that data and take care of data integrity?

There’s also one more point to consider, which is that end-to-end tests are extremely brittle. They can fail for a number of reasons that are not related to bugs in code. I’m not saying that end-to-end tests don’t bring any value - quite the contrary. But at some point of complexity, one has to calculate the costs vs. gains. Consumer-driven contracts comes to the rescue. Performing contract testing can break your builds at a very early stage if your communication is breaking the contract. In other words, if you have a typo in your message then it’s better to fail in the 1st minute of your build and not the last minute of your 2-hour lasting end-to-end tests.

This might be controversial, but personally I believe that when you set things up properly, then end-to-end testing is redundant and can be omitted completely. The condition for this is that you 1) do contract testing, 2) have monitoring and alerting over your key performance indicators, and 3) can do rollback testing and build it into your deployment pipeline. You can check out the Spring Cloud Pipelines project for an example of such a deployment pipeline.

InfoQ: Tell me about the new integration with Spring Rest Docs, and whether or not it might alter the typical consumer-driven contracts workflow.

Grzejszczak: It’s not that new but indeed it’s getting more attention. Some users don’t like writing Groovy DSLs and don’t want their tests to be generated. They want to fully own the testing process. There are other users who already are using Spring Rest Docs to test their code. Dave Syer is one of those users and it was his idea to add Spring Cloud Contract integration to Spring Rest Docs. Thanks to this you can write tests to test your web application and also automatically produce stubs. With the latest version of Spring Cloud Contract, you can also generate a Groovy DSL contract from Spring Rest Docs.

As for the workflow - I can imagine consumers pairing up with producers to develop the tests and stubs that would suit the needs of the consumers. That way the process would be maintained. On the other hand, something tells me that Spring Rest Docs approach will be more often used in the "producer contract" approach- so the one where the producer defines how the contract looks like. In Spring we like to eat our own dog food, and Spring Initilizr (the code behind is already using Spring Cloud Contract and the Spring Initilizr stubs are getting published to our Spring’s Maven repository.

InfoQ: Finally, could you talk about anything interesting that you have coming up on your roadmap?

Grzejszczak: We have only just released a fresh new "1.1.0.RELEASE" version of Spring Cloud Contract that brings quite a few interesting features including full modularization (now you can provide your own custom parts of Spring Cloud Contract, such as for example generating PHP tests) so most likely in the upcoming weeks we will be working on stabilizing the API and fixing bugs. As for the longer term plans, we are thinking of making things easier for non-Java users. But obviously the most important for us is the feedback from our users, and we will adjust our plans to satisfy their needs.

If you want to know more about the project, check out its homepage. If you want to ask some questions you can find me on Gitter or you can ping me on Twitter @mgrzejszczak.

Rate this Article