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