End to end testing for microservices with Spring Cloud Contract Stub Runner

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.

f:id:jyukutyo:20170530184732p:plain

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

f:id:jyukutyo:20170602122633p:plain

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.

f:id:jyukutyo:20170602155313p:plain

Difference between production and test environment

Production

f:id:jyukutyo:20170602155937p:plain

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

f:id:jyukutyo:20170602155951p:plain

Now we can test error cases where a specific microservice returned an error HTTP status with Spring Cloud Contract Stub Runner.