Wiremock + Juni5 + GrahQL Integration Tests

How Wiremock Helps with GraphQL #

Dependence on test data #

It is common for Microservices to call other downstream services. The coordination to make sure all services have reliable test data in-sync with other services is exponentially hard. Thus the need for contract-driven development, which allows simultaneous development of services that depend on each other.

Another positive side effect of writing tests using Wiremock: having deterministic CICD regression testing.

Testing of network settings #

Wiremock allows for more test coverage because it validates the application properties loaded by the Spring application context - differently unit tests or other frameworks such as mockwebserver.

Testing negative Cases #

Wiremock allows the testing of negative use cases because it supports stubbing of alternative HTTP response codes, random response bodies, and slow network responses.

Code #

Wiremock can be used to isolate and parallelize the development of contract-driven features because it allows the stubbing of responses based on contracts. See examples below using Kotlin:

WireMock.stubFor allows creating stubs for REST endpoints based on headers, request path, and body:

wiremockServer.stubFor(post(urlEqualTo("/endpoint"))
        .withRequestBody(equalToJson("""{"entries": [{"key": "value"]}"""))
        .willReturn(aResponse()
                .withHeader("Content-Type", "application/json")
                .withBody("""{
                    |"payload": {
                    |    "entries": [
                    |        {
                    |            "key": "value"
                    |        }
                    |    ]
                    |},
                    |"status": 200
                }""".trimMargin())))

Junit5 + Spring initializer to start/stop wiremock:

class WireMockContextInitializer : ApplicationContextInitializer<ConfigurableApplicationContext> {
    override fun initialize(applicationContext: ConfigurableApplicationContext) {
        val wmServer = WireMockServer(WireMockConfiguration().port(9095))
        wmServer.start()
        applicationContext.beanFactory.registerSingleton("wireMock", wmServer)
        applicationContext.addApplicationListener {
            if (it is ContextClosedEvent) {
                wmServer.stop()
            }
        }
    }
}

Full example using RestAssured, Springboot, and Junit 5 to test the localserver.

@SpringBootTest(classes = [Application::class],
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
        properties = ["externalEndpointBaseUrl=http://localhost:9095/endpoint"])
@ContextConfiguration(initializers = [WireMockContextInitializer::class])
class ApiTest(
    @LocalServerPort val port: Int,
    @Autowired val wmServer: WireMockServer
) {
    @Test
    fun `get external call information and return in the graphql response`() {
        wmServer.stubFor(post(urlEqualTo("/endpoint"))
                .withRequestBody(equalToJson("""{"body": [{"key": "value"]}"""))
                .willReturn(aResponse()
                        .withHeader("Content-Type", "application/json")
                        .withBody("""{
                            |"payload": {
                            |    "entries": [
                            |        {
                            |            "key": "value"
                            |        }
                            |    ]
                            |},
                            |"status": 200
                        }""".trimMargin())))
 
        RestAssured.given()
                .filter(ResponseLoggingFilter())
                .contentType(ContentType.JSON)
                .body("{\"query\":\"{\\n object(param1: { entry: \\\"value\\\"}) " +
                        "{\\n key\\n }\\n}\\n \"}")
                .`when`().log().all()
                .post("http://localhost:$port/graphql")
                .then().log().all()
                .statusCode(200)
                .body("data.entries.key", equalTo("value"))
                .log().all()
 
        wmServer.verify(postRequestedFor(urlEqualTo("/entrypoint"))
                .withRequestBody(equalToJson("""{"body": [{"key": "value"]}"""))
        )
    }
}