In modern applications, your services often communicate with external APIs — payment gateways, third-party authentication, messaging platforms, etc. During integration testing, relying on these actual external systems can make your tests:
- Slow
- Flaky
- Dependent on internet access
Enter WireMock, a powerful HTTP mocking tool that lets you stub external API behavior in your integration tests. In this post, you’ll learn how to implement WireMock Integration Testing with Spring Boot and gain full control over external service responses.

⚙️ Project Setup
Let’s assume we’re building a CustomerService
that calls an external “CRM API” to fetch user data. We’ll mock this external API using WireMock.
🧾 Maven Dependencies
Add these to your pom.xml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.github.tomakehurst</groupId> <artifactId>wiremock-jre8</artifactId> <version>2.35.0</version> <scope>test</scope> </dependency> |
📁 Package: com.kscodes.springboot
Let’s set up our project.
Customer.java
1 2 3 4 5 6 7 8 9 10 11 |
package com.kscodes.springboot.model; public class Customer { private Long id; private String name; // Getters and Setters } |
CustomerService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package com.kscodes.springboot.service; import com.kscodes.springboot.model.Customer; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @Service public class CustomerService { private final RestTemplate restTemplate; private final String crmBaseUrl; public CustomerService(RestTemplate restTemplate, @Value("${crm.api.url}") String crmBaseUrl) { this.restTemplate = restTemplate; this.crmBaseUrl = crmBaseUrl; } public Customer getCustomerById(Long id) { return restTemplate.getForObject(crmBaseUrl + "/customers/" + id, Customer.class); } } |
RestTemplateConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package com.kscodes.springboot.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } } |
🧪 Writing the WireMock Integration Test
Here’s how to write a test using WireMock Integration Testing with Spring Boot:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
package com.kscodes.springboot; import com.kscodes.springboot.model.Customer; import com.kscodes.springboot.service.CustomerService; import com.github.tomakehurst.wiremock.junit5.WireMockTest; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.test.context.ContextConfiguration; import static com.github.tomakehurst.wiremock.client.WireMock.*; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest @WireMockTest(httpPort = 8081) @ContextConfiguration(initializers = CustomerServiceTest.Initializer.class) public class CustomerServiceTest { @Autowired private CustomerService customerService; static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { public void initialize(ConfigurableApplicationContext context) { TestPropertyValues.of("crm.api.url=http://localhost:8081") .applyTo(context.getEnvironment()); } } @Test void shouldReturnMockedCustomerFromWireMock() { stubFor(get(urlEqualTo("/customers/1")) .willReturn(aResponse() .withHeader("Content-Type", "application/json") .withBody(""" { "id": 1, "name": "Mocked Customer" } """))); Customer customer = customerService.getCustomerById(1L); assertThat(customer.getName()).isEqualTo("Mocked Customer"); } } |
💡 How It Works
@WireMockTest(httpPort = 8081)
starts an embedded WireMock server- We override the
crm.api.url
to hit WireMock, not the real CRM stubFor(...)
defines the behavior of the mock endpoint- We validate that
CustomerService
correctly handles the mock response
📚 Advantages of WireMock Integration Testing with Spring Boot
Feature | Benefit |
---|---|
🧪 Fully isolated | No dependency on real APIs |
⚡ Fast and repeatable | Mocking gives full control |
🧩 Easy to customize | Simulate 200, 404, 500 responses |
🔄 Test edge cases | Simulate timeouts and delays |
⚠️ Bonus: Testing Error Scenarios
You can easily test how your service reacts to a 404 Not Found
:
1 2 3 4 5 |
stubFor(get(urlEqualTo("/customers/2")) .willReturn(aResponse().withStatus(404))); |
Test logic would assert that an exception or null is handled gracefully.
✅ Best Practices
- Use
@WireMockTest
over manual server spin-up for simplicity - Externalize API URLs using
@Value
and profiles - Add delay simulation:
.withFixedDelay(2000)
- Store stubs in files for reuse with
WireMockServer.loadMappingsFrom(...)
📚 Summary
In this post, you learned how to use WireMock Integration Testing with Spring Boot to isolate and simulate external APIs during testing. You now know how to:
- Configure WireMock in tests
- Stub custom HTTP responses
- Inject mock endpoints using dynamic properties
- Handle API failures and edge cases
WireMock gives you confidence that your service will behave correctly even when APIs are slow, fail, or respond unexpectedly.