I’m dividing a Monolith application into microservices. I have end to end test scenarios. So after I moved one function to a microservice, I tried to re-test these scenarios. But I had a problem in an error case. For example, in a case where a specific microservice returned an error HTTP status. This diagram shows the case.
Do I have to rewrite code in microservice to throw an exception? No, there is no need for that. I use Spring Cloud Contract Stub Runner. With Stub Runner, I didn’t rewrite and achieved the test goal. The client application communicate not with a real microservice, with a stub application.
What is Spring Cloud Contract?
Spring Cloud Contract Stub Runner is included in Spring Cloud Contract. Spring Cloud Contract is one of the Consumer-driven contracts frameworks. For more detail, read the following article of InfoQ.com.
www.infoq.com
I officially translated this article into Japanese.
www.infoq.com
Quick start
I show example code. You can find full code in the following GitHub repository.
github.com
To define stub behavior, all I need is writing Groovy DSL.
package contracts
org.springframework.cloud.contract.spec.Contract.make {
request {
method 'POST'
url '/example'
body([
"id": 12345
])
}
response {
status 201
body([
name: "john"
])
headers {
contentType('application/json;charset=UTF-8')
}
}
}
This DSL defines a POST request. When I send a request to “/example” with “id=12345”, I can get a 201 response.
Then I run a Maven command to package and put a stub into Maven repository (local or in-house repository).
Finally, I can run a stub runner with a stub.
$ java -jar -Dstubrunner.ids=com.jyukutyo:stub-example stub-runner.jar
The stub is running at a random port (I express how to get the port later).
$ curl -D- -X post -H 'Content-Type:application/json' -d "{"id":12345}" http://localhost:14161/example
HTTP/1.1 201 Created
Content-Type: application/json;
charset=utf-8
Transfer-Encoding: chunked
Server: Jetty(9.3.16.v20170120)
{"name":"john"}
I got it!
Detail
WireMock
Spring Cloud Contract Stub Runner run a stub application with WireMock.
wiremock.org
WireMock is a simulator for HTTP-based APIs. In WireMock, stubs can be configured via JSON files.
Groovy DSL
Spring Cloud Contract converts Groovy DSLs into WireMock style JSON files.
mvn install
Above DSL is converted into the following JSON file.
{
"uuid" : "cf94db5c-6a65-4c4e-91b7-5b473019a71a",
"request" : {
"url" : "/example",
"method" : "POST",
"bodyPatterns" : [ {
"matchesJsonPath" : "$[?(@.id == 12345)]"
} ]
},
"response" : {
"status" : 201,
"body" : "{\"name\":\"john\"}",
"headers" : {
"Content-Type" : "application/json;charset=UTF-8"
}
}
}
You can find the meaning of JSON on WireMock web site.
By install or deploy command, the JSON is included in JAR file.
Stub application
If you use In-house repository such as Artifactory, you need to add the Artifactory URL on application.yml of Stub Runner.
stubrunner:
repositoryRoot: http://example.com:9999/artifactory/libs-snapshot-local/
When I run the following command, Stub Runner download the JAR file and run a stub application with the JSON in JAR.
$ java -jar -Dstubrunner.ids=com.jyukutyo:stub-example stub-runner.jar
Stub Runner with Eureka
I’m using Eureka, which is a service discovery and has been developed as Netflix OSS. We can easily integrate Stub Runner with Eureka.
All you need is add Eureka URL on application.yml.
eureka:
client:
serviceUrl:
defaultZone: http://example.com:10000/eureka/
You can specify an application name of the stub application as a option parameter to register it to Eureka.
java -jar -Dstubrunner.ids=[groupId]:[artifactId] -Dstubrunner.idsToServiceIds.[artifactId]=hoge stub-runner.jar
After starting the stub application, Stub Runner registers its url to Eureka.
Difference between production and test environment
Production
The client application doesn’t know whether it connects with a real application or a stub application. There is no need for changing the client application code and configuration because it gets microservice URL from Eureka.
Test
Now we can test error cases where a specific microservice returned an error HTTP status with Spring Cloud Contract Stub Runner.