Integrate Wiremock and Quarkus in Testing for Mocking API Response

There are multipe ways of testing API connectivity from one service to another, in Integration Testing we can do direct connectivity or using an external API mocking such as Microcks. But for a simple Unit Testing, we can leverage Wiremock to do this.

And in this writings, i will try to integrate Wiremock with Quarkus for Unit Testing. First, lets start with a simple Maven pom file

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.edw</groupId>
    <artifactId>quarkus-and-wiremock</artifactId>
    <version>1.0</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <compiler-plugin.version>3.11.0</compiler-plugin.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <skipITs>true</skipITs>
        <surefire-plugin.version>3.1.2</surefire-plugin.version>

        <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
        <quarkus.platform.group-id>com.redhat.quarkus.platform</quarkus.platform.group-id>
        <quarkus.platform.version>3.2.6.SP1-redhat-00001</quarkus.platform.version>
    </properties>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>quarkus-bom</artifactId>
                <version>${quarkus.platform.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-arc</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy</artifactId>
        </dependency>

        <!-- external call -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-rest-client</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-rest-client-jackson</artifactId>
        </dependency>

        <!-- Test -->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.wiremock</groupId>
            <artifactId>wiremock</artifactId>
            <version>3.3.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Lets create a simple Rest API client,

package com.edw.client;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import java.util.HashMap;

@Path("/")
@RegisterRestClient
public interface MockyService {
    @GET
    @Path("/")
    HashMap getDefaultMockData();
}

Its configuration file,

# default
quarkus.http.port=8080
quarkus.log.level=INFO
quarkus.log.category."com.edw".level=DEBUG
quarkus.log.category."org.apache.http".level=INFO

# disable sending anonymous statistics
quarkus.analytics.disabled=true

quarkus.rest-client."com.edw.client.MockyService".url=https://run.mocky.io/v3/99687692-4390-4ca2-816a-35c015fd72d0

And lets call it from our Controller,

package com.edw.controller;

import com.edw.client.MockyService;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

import java.util.HashMap;

import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Path("/")
public class IndexController {

    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    @Inject
    @RestClient
    MockyService mockyService;

    @GET
    @Path("/call")
    @Produces(MediaType.APPLICATION_JSON)
    public Response callExternalUrl() {
        logger.debug("calling external-service");
        return Response
                .status(200)
                .entity(mockyService.getDefaultMockData())
                .build();
    }
}

We can do some curl test by hitting the endpoint directly thru a curl command,

$ curl -kv http://localhost:8080/call
*   Trying ::1:8080...
* TCP_NODELAY set
*   Trying 127.0.0.1:8080...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /call HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.65.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: application/json
< content-length: 17
<
* Connection #0 to host localhost left intact
{"hello":"world"}                                   

Now, lets try to do a unit testing to simulate this external API call. We can start by setting up a Wiremock server that will mocking a specific API endpoint

package com.edw.config;

import com.github.tomakehurst.wiremock.WireMockServer;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;

import java.util.HashMap;
import java.util.Map;

import static com.github.tomakehurst.wiremock.client.WireMock.*;

public class WiremockConfig implements QuarkusTestResourceLifecycleManager {
    private WireMockServer server;

    @Override
    public Map<String, String> start() {
        server = new WireMockServer(8082);
        server.start();
        server.stubFor(
                get(urlEqualTo("/"))
                        .willReturn(aResponse()
                                .withStatus(200)
                                .withHeader("Content-Type", "application/json")
                                .withBody("{\"hello\": \"mock\"}")));

        return new HashMap<>();
    }

    @Override
    public void stop() {
        if (server != null) {
            server.stop();
        }
    }
}

For testing, we create a new properties file which is pointint to our Wiremock server

# default
quarkus.log.level=INFO
quarkus.log.category."com.edw".level=DEBUG
quarkus.log.category."org.apache.http".level=DEBUG

# disable sending anonymous statistics
quarkus.analytics.disabled=true

quarkus.rest-client."com.edw.client.MockyService".url=http://localhost:8082

Lastly, lets create a new test case for this. Simulating a curl call to our endpoint

package com.edw.controller;

import com.edw.config.WiremockConfig;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.isA;

@QuarkusTest
@QuarkusTestResource(WiremockConfig.class)
public class IndexControllerTest {

    @Test
    public void testCall() {
        given()
            .when()
                .get("/call")
                .then()
            .statusCode(200)
                .body("hello", isA(String.class))
                .body("hello", equalTo("mock"))
            .log().all();
    }
}

The whole code for this post can be clone on below repository,

https://github.com/edwin/quarkus-and-wiremock

Leave a Comment

Your email address will not be published.