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.
Join the DZone community and get the full member experience.
Join For FreeWireMock 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.
Opinions expressed by DZone contributors are their own.
Comments