Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Using WireMock to Mock Underlying Services for REST Testing in Spring Boot

DZone's Guide to

Using WireMock to Mock Underlying Services for REST Testing in Spring Boot

Learn how the WireMock simulator can be used to mock an API response while testing your REST services developed in Spring Boot.

· Integration Zone
Free Resource

Modernize your application architectures with microservices and APIs with best practices from this free virtual summit series. Brought to you in partnership with CA Technologies.

WireMock is a simulator for HTTP-based APIs and can be used to mock an API response in case of REST services development and testing. In this article, we will focus on how WireMock can be used to mock an API response while testing REST service that you are developing in SpringBoot. In this way, you can simulate scenarios for which getting test data is time-consuming in the real world. I used it in integration testing Gateway APIs to mock API responses for the underlying services that we were using.

Including WireMock in Project as a Dependency

As mentioned by http://www.wiremock.org, it is currently recommended that you use the standalone JAR as a dependency with Spring Boot projects. This avoids a conflict over the Jetty version.

<dependency>
      <groupId>com.github.tomakehurst</groupId>
      <artifactId>wiremock-standalone</artifactId>
      <version>2.6.0</version>      
</dependency>

Writing the Integration Test

JUnit now has a Classrule for WireMock to handle the lifecycle and setup/tear-down tasks.

@ClassRule public static WireMockRule wireMockRule = new WireMockRule( options().port(8090).httpsPort(8443).notifier(new ConsoleNotifier(true)));

With this, WireMock now runs at port 8090/8443 and can serve HTTP(s) request on that port. Also set up ConsoleNotifier to see all the WireMock notifications (data available/returned) on the console. Any API that you want to mock has to point to WireMock at the specified port, so that data is now served from WireMock. For example, if your service runs at http://www.someserver.com/api/path/resource , then you have to change it in your testing tohttp://localhost:8080/api/path/resource .

Spring provides an easy way to achieve this with "Spring Profile." You can set your "Test" profile in application.yaml with all the APIs that have to be mocked to point to the WireMock port.

spring:
    profiles: integration
clients:
  blah:
    server: http://localhost:8090
resource: /api/path/v1.0/resourcename
  otherblah:
      server: http://localhost:8090

Now, when you write your integration test in Spring, you specify a particular profile to use.

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = YourApplication.class, 
                webEnvironment=WebEnvironment.DEFINED_PORT)
@ActiveProfiles("integration")
@Profile("integration")
public class YourWiremockTest {

Before you write your actual test, you can set up the response data for the underlying APIs that you want to use mock, record, and replay kind of statements:

wireMockRule.stubFor(post(urlPathMatching("/api/path/v1.0/resourcename"))
  .withRequestBody(containing("\"somethinginheader\":\"50cca0e4-69ea-4247\""))
  .willReturn(aResponse()
  .withStatus(200)
  .withHeader("Content-Type", APPLICATION_JSON)
  .withBody(fileToJSON("datafile.with.data.json"))));

Let's take a look at these statements.

Stub for wireMockRule.stubFor(post(urlPathMatching("/api/path/v1.0/resourcename"))

Match on criteria:withRequestBody(containing("\"somethinginheader\":\"50cca0e4-69ea-4247\""))

Specify the header and HTTP code for the response:.willReturn(aResponse() .withStatus(200) .withHeader("Content-Type", APPLICATION_JSON)

Last, the response withBody(fileToJSON("datafile.with.data.json"))))

Remaining task is executing the functionality under test and assertions

Response response = someController.functionalityUnderTest();
//Check response status
Assert.assertTrue(response.getStatus()==200);
//Check return type
Assert.assertTrue(response.getEntity() != null);
Assert.assertTrue(response.getEntity() instanceof  SomeTypeOfList);

CI/CD Integration

These tests can be included in a Jenkins (or any other CI tool) build to run with or without the code build (better to run as a separate build) and it runs like any other JUnit test case.

Share your experience with using WireMock.

The Integration Zone is proudly sponsored by CA Technologies. Learn from expert microservices and API presentations at the Modernizing Application Architectures Virtual Summit Series.

Topics:
wiremock ,spring boot ,integration testing ,testing ,spring ,mock objects ,integration

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}