API Consumer-Contract Tests and Test Doubles With Karate
Join the DZone community and get the full member experience.Join For Free
One of the features in the works (and close to being released) is the ability to spin-up test-doubles to “mock” a web-service API dependency that may still be in development — or for which a test-environment may be unavailable or unstable. This is a significant pain-point for many teams — and “flaky integration tests” are legendary sources of pain for many a platform team dealing with micro-services.
You can find a comprehensive list of capabilities in the project documentation. While the README evolves, a demo end-to-end example using Spring Boot has been created as an early preview for the community, and is summarized below.
We use a simplified example of a Java consumer which makes HTTP calls to a Payment Service (provider) where
DELETE have been implemented. The provider implements CRUD for the
Payment.java POJO, and the
POST (or create) results in a message (
Shipment.java as JSON) being placed on a queue, which the consumer is listening to.
ActiveMQ is being used for the sake of mixing an asynchronous flow into this example, and with the help of some simple utilities, we are able to mix asynchronous messaging into a Karate test as well as the test-double.
The 'consumer' or client application that consumes the demo 'Payment Service' and also listens to a queue
The provider 'Payment Service' implemented in Spring Boot and using an in-memory data-store
An end-to-end integration test of the consumer that needs the real provider to be up and running
A 'normal' Karate functional-test that tests the 'contract' of the Payment Service from the perspective of the consumer
JUnit runner for the above Karate 'contract' test, that depends on the real provider being up and running
A 'state-ful' mock (or stub) that fully implements the 'contract' ! Yes, really.
Uses the above 'stub' to run the Payment Service 'contract' test
Uses the 'fake' Payment Service 'stub' to run an integration test for the real consumer
Karate can act as a proxy with 'gateway like' capabilities, you can choose to either stub a response or delegate to a remote provider, depending on the incoming request. Think of the 'X' as being able to transform the HTTP request and response payloads as they pass through (and before returning)
Here Karate is set up to act as an HTTP proxy, the advantage is that the consumer can use the 'real' provider URL, which simplifies configuration, provided that you can configure the consumer to use an HTTP proxy (ideally in a non-invasive fashion)
Karate acts as a URL 're-writing' proxy. Here the consumer 'knows' only about the proxy. In this mode (as well as the above 'HTTP proxy' mode which uses the same script file), you can choose to either stub a response - or even forward the incoming HTTP request onto any remote URL you choose.
Karate on the "other side of the fence" (handling HTTP requests instead of making them) turns out to be remarkably effective, yet simple.
Native support for expressing JSON and XML
Manipulate or even transform payloads
Validate payloads, using a simpler alternative to JSON schema if needed
Karate is all about making HTTP calls, giving you the flexibility to call downstream services if needed
In-memory JSON and JsonPath solves for state and filtering if needed
Easily seed data or switch environment/config on start
If you think about it, all the above are sufficient to implement any microservice. Karate’s DSL syntax is focused on exactly these aspects, thus opening up interesting possibilities.
It may be hard to believe that you can spin up a usable microservice in minutes with Karate — but do try it and let me know what you think!
Published at DZone with permission of Peter Thomas. See the original article here.
Opinions expressed by DZone contributors are their own.