Mocking OpenAPI services using WireMock

This document describes how to mock OpenAPI services using WireMock. The testing procedure described in this document is based on the serverless-workflow-service-calls-quarkus example application.

WireMock is an open source Mocking API for unit, integration, and performance tests. You can use WireMock to isolate your tests from third party APIs and prototype APIs that do not exist.

Prerequisites

The examples used in this document assumes that you have the following prerequisites:

Adding a mocked OpenAPI service to your tests

The procedure in this section describes how you can add WireMock to your workflow application.

Prerequisites
Procedure
  1. Add the following WireMock dependency to the pom.xml file of your project:

    Add WireMock dependency to pom.xml
    <dependency>
        <groupId>com.github.tomakehurst</groupId>
        <artifactId>wiremock-jre8</artifactId>
        <version>{wiremock.version}</version>
        <scope>test</scope>
    </dependency>

    Replace {wiremock.version} variable with the version of WireMock that you want to use.

  2. Select one of the following methods to start your WireMock server:

    • You can start the WireMock server as a QuarkusTestResource. If you select this method, then the WireMock server is started once before you run any test, and the server is stopped when the test finishes. This option is suitable for most use cases.

    • You can start the WireMock server independently for each test. This option is useful when you want each test to behave differently.

    For more information about starting the WireMock server, see Starting WireMock server as a QuarkusTestResource and Starting WireMock server for a specific test.

  3. Start the WireMock server as shown in the following example:

    Example of starting a WireMock server
    WireMockConfiguration config = WireMockConfiguration.wireMockConfig().dynamicPort(); (1)
    WireMockServer wireMockServer = new WireMockServer(config); (2)
    wireMockServer.start(); (3)
    1 Creates the configuration for the WireMock server. You can use a dynamic port since it prevents the tests from failing due to port conflicts. When you cannot use a dynamic port, you can use the WireMockConfiguration#port(int) method to use a fixed port number.
    2 Creates the WireMock server instance.
    3 Starts the WireMock server.
  4. Mock the endpoints as shown in the following example:

    Example of mocking endpoints
    ObjectMapper objectMapper = new ObjectMapper();
    JsonNode greecePayload = objectMapper.readTree(getClass().getResourceAsStream("/country_mock.json")); (1)
    
    wireMockServer.stubFor(WireMock.get(WireMock.urlEqualTo("/rest/v2/name/Greece")) (2)
                                   .willReturn(WireMock.aResponse() (3)
                                                       .withStatus(200) (4)
                                                       .withHeader("Content-Type", "application/json") (5)
                                                       .withJsonBody(greecePayload))); (6)
    1 Creates the JSON payload, which the WireMock server returns. Alternatively, you can use the ResponseDefinitionBuilder#withBody method to define a String or a byte[] as the response body.
    2 Defines a stub for the /rest/v2/name/Greece endpoint.
    3 Defines the response for the stub.
    4 Defines the response status.
    5 Defines the response headers.
    6 Defines the response body.
  5. Stop the WireMock server as shown in the following example:

    Example of stopping a WireMock server
    wireMockServer.stop();

Starting WireMock server as a QuarkusTestResource

In the process of adding a mocked OpenAPI service to your tests, you need to start the WireMock server. You can start the WireMock server either as a QuarkusTestResource or you can start the server for each test.

The procedure in this section describes how you can start the WireMock server as a QuarkusTestResource. For more information about QuarkusTestResource, see Starting services before the Quarkus application starts document.

Prerequisites
Procedure
  1. Create a class that implements the QuarkusTestResource interface as shown in the following example:

    Example implementation of QuarkusTestResource
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.github.tomakehurst.wiremock.WireMockServer;
    import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
    import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
    
    import java.io.IOException;
    import java.io.UncheckedIOException;
    import java.util.Map;
    
    import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
    import static com.github.tomakehurst.wiremock.client.WireMock.get;
    import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
    
    public class RestCountriesMockServer implements QuarkusTestResourceLifecycleManager {
    
        private WireMockServer wireMockServer;
    
        @Override
        public Map<String, String> start() { (1)
            configureWiremockServer();
            return Map.of("quarkus.rest-client.restcountries_json.url", wireMockServer.baseUrl() + "/rest"); (2)
        }
    
        private void configureWiremockServer() {
            wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().dynamicPort());
            wireMockServer.start();
    
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode greecePayload;
            try {
                greecePayload = objectMapper.readTree(getClass().getResourceAsStream("/country_mock.json"));
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
            wireMockServer.stubFor(get(urlEqualTo("/rest/v2/name/Greece"))
                                           .willReturn(aResponse()
                                                               .withStatus(200)
                                                               .withHeader("Content-Type", "application/json")
                                                               .withJsonBody(greecePayload)));
        }
    
        @Override
        public void stop() { (3)
            if (wireMockServer != null) {
                wireMockServer.stop();
            }
        }
    }
    1 Starts the test resource. This method is called once before running all the tests.
    2 Returns a map of application properties that are set in the test environment. In this case, the quarkus.rest-client.restcountries_json.url property is set as the base URL of the WireMock server.
    3 Stops the test resource. This method is called once after running all the tests.
  2. Use the QuarkusTestResource implementation in your test class as shown in the following example:

    Example of a test class using the QuarkusTestResource implementation
    import io.quarkus.test.common.QuarkusTestResource;
    import io.quarkus.test.junit.QuarkusTest;
    import org.junit.jupiter.api.Test;
    
    @QuarkusTest
    @QuarkusTestResource(RestCountriesMockServer.class) (1)
    class CountryServiceWorkflowTest {
    
        @Test
        void testFeatureA() {
            // ...
        }
    
        @Test
        void testFeatureB() {
            // ...
        }
    }
    1 Uses the RestCountriesMockServer class as a test resource.

Starting WireMock server for a specific test

You can also start the WireMock server to be used in a specific test.

Prerequisites
Procedure
  1. Wrap the logic of a test between starting and stopping the WireMock server as shown in the following example:

    Example of a test using a specific WireMock server instance
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.github.tomakehurst.wiremock.WireMockServer;
    import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
    import io.quarkus.test.junit.QuarkusTest;
    import org.junit.jupiter.api.Test;
    
    import java.io.IOException;
    
    import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
    import static com.github.tomakehurst.wiremock.client.WireMock.get;
    import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
    
    @QuarkusTest
    class CountryServiceWorkflowTest {
    
        @Test
        void testFeatureA() throws IOException {
            WireMockServer wireMockServer = startWiremockServerForFeatureA();
            try {
                // test logic
            } finally {
                wireMockServer.stop();
            }
        }
    
        @Test
        void testFeatureB() {
            WireMockServer wireMockServer = startWiremockServerForFeatureB();
            try {
                // test logic
            } finally {
                wireMockServer.stop();
            }
        }
    
        private static WireMockServer startWiremockServerForFeatureA() throws IOException {
            WireMockServer wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().dynamicPort());
            wireMockServer.start();
    
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode greecePayload = objectMapper.readTree(CountryServiceWorkflowTest.class.getResourceAsStream("/country_mock_feature_a.json"));
            wireMockServer.stubFor(get(urlEqualTo("/rest/v2/name/Greece"))
                                           .willReturn(aResponse()
                                                               .withStatus(200)
                                                               .withHeader("Content-Type", "application/json")
                                                               .withJsonBody(greecePayload)));
    
            return wireMockServer;
        }
    
        private static WireMockServer startWiremockServerForFeatureB() {
            WireMockServer wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().dynamicPort());
            wireMockServer.start();
    
            wireMockServer.stubFor(get(urlEqualTo("/rest/v2/name/Greece"))
                                           .willReturn(aResponse().withStatus(404)));
    
            return wireMockServer;
        }
    }

You can test your workflow application using the instructions described in Testing your workflow application using REST Assured document.

Found an issue?

If you find an issue or any misleading information, please feel free to report it here. We really appreciate it!