REST API Integration Testing with Wiremock

Lets say you have a service (customer-service) that calls another service (account-service) over HTTP, gets the response from account-service, does some munging with the data and returns it back to the UI.

Now like a good developer, you are trying to test customer-service to verify that it is adhering to the requirements contract. How do you test the service such that it goes through the system flow, makes the necessary calls to account service and returns responses?

Assuming that the account-service is configured to be available at http://localhost:8090, we can configure Wiremock [1] [1:1] to intercept all calls going to localhost:8090 and return stubbed responses.

Here's a sample Integration Test:

    WireMockServer wireMockServer = new WireMockServer(wireMockConfig().port(8090))
    WireMock wireMock = new WireMock("localhost", 8090)
    def baseUrl = 'http://localhost:8889/customerservice/v1/customerInfo'

    def setup() {
        wireMockServer.start()
    }

    def cleanup() {
        wireMockServer.stop()
    }

    def "get customer info"() {
        given:
        wireMock.register(get(urlPathEqualTo( "/accountservice/v1/account/account1234"))
                .willReturn(aResponse()
                .withStatus(200)
                .withHeader("Content-Type", "application/json")
                .withBody(JSON_RESPONSE_DATA))
        )

        def http = new HTTPBuilder(baseUrl)
        def headers = ['Accept': 'application/json', 'Content-Type': 'application/json', 'X-FORWARDED-FOR': '1.2.3.4']
        def requestBody = '{"customerNumber":"cust1234","ZipCode":"12345"}'

        http.handler.failure = http.handler.success

        when:
        def response = http.post(contentType: ContentType.JSON, headers: headers, body: requestBody)

        then:
        wireMock.verifyThat(new RequestPatternBuilder(RequestMethod.GET, urlPathEqualTo("/accountservice/v1/account/account1234")))
        response
        !response.errors
    }

Line: 1-2 are setting up Wiremock server to respond to http requests to http://localhost:8090 (account-service in this case)

Line 5: Starts the wiremock proxy server before each test.

Line 9: Stops the wiremock proxy server after each test.

Line 14: Stubs the wiremock for a GET call for path matching /accountservice/v1/account/account1234

Line 15-19: Will return a 200 response with response body defined as a String in JSON_RESPONSE_DATA

Line 29: Calls the actual service via HTTP Post based on the baseUrl defined on line 3 with headers and request body defined on line 22 and 24.

Line 32: Verifies that the wiremock call was actually called.

Line 34-35: Verify that there was a valid response and response had no error.

Note:
The test code is written in Groovy and is using Spock[1:2] test framework but you can also use Java along with JUnit as the test framework.

To add the wiremock library to your code (via pom.xml)

<dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock</artifactId>
    <version>1.57</version>

    <exclusions>
        <exclusion>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>servlet-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>   

In summary:

You can mock any external http/RESTful service based on the host and port you expect it at. Just configure Wiremock server to listen to that host and port, and start the wiremock server. Wiremock then would intercept all the calls that are made to that host and port.

Advantages:

a. Mock external services based on the contracts they provide.
b. Verify marshaling and un-marshaling of JSON/XML data to their respective objects.
c. Test your service end-points as if they are being called via external HTTP calls and verify parameter naming and marshaling to request object.
d. Verify contracts provided by your service (and other external services).

That's it. Thank you for reading. Please let me know if you have any thoughts/questions/feedback via comments below.

References:

  1. Spock Test Framework ↩︎ ↩︎ ↩︎