---
name: unit-test-wiremock-rest-api
description: Provides patterns for unit testing external REST APIs using WireMock. Stubs API responses, verifies request details, simulates failures (timeouts, 4xx/5xx errors), and validates HTTP client behavior without real network calls. Use when testing service integrations with external APIs or mocking HTTP endpoints.
allowed-tools: Read, Write, Bash, Glob, Grep
---
# Unit Testing REST APIs with WireMock
## Overview
Patterns for testing external REST API integrations with WireMock: stubbing responses, verifying requests, error scenarios, and fast tests without network dependencies.
## When to Use
- Testing services calling external REST APIs
- Stubbing HTTP responses for predictable test behavior
- Testing error scenarios (timeouts, 5xx errors, malformed responses)
- Verifying request details (headers, query params, request body)
## Instructions
1. **Add dependency**: WireMock in test scope (Maven/Gradle)
2. **Register extension**: `@RegisterExtension WireMockExtension` with `dynamicPort()`
3. **Configure client**: Use `wireMock.getRuntimeInfo().getHttpBaseUrl()` as base URL
4. **Stub responses**: `stubFor()` with request matching (URL, headers, body)
5. **Execute and assert**: Call service methods, validate results with AssertJ
6. **Verify requests**: `verify()` to ensure correct API usage
**If stub not matching**: Check URL encoding, header names, use `urlEqualTo` for query params.
**If tests hanging**: Configure connection timeouts in HTTP client; use `withFixedDelay()` for timeout simulation.
**If port conflicts**: Always use `wireMockConfig().dynamicPort()`.
## Examples
### Maven Dependencies
```xml
org.wiremock
wiremock
3.4.1
test
org.assertj
assertj-core
test
```
### Basic Stubbing and Verification
```java
import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.assertj.core.api.Assertions.assertThat;
class ExternalWeatherServiceTest {
@RegisterExtension
static WireMockExtension wireMock = WireMockExtension.newInstance()
.options(wireMockConfig().dynamicPort())
.build();
@Test
void shouldFetchWeatherDataFromExternalApi() {
wireMock.stubFor(get(urlEqualTo("/weather?city=London"))
.withHeader("Accept", containing("application/json"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("{\"city\":\"London\",\"temperature\":15,\"condition\":\"Cloudy\"}")));
String baseUrl = wireMock.getRuntimeInfo().getHttpBaseUrl();
WeatherApiClient client = new WeatherApiClient(baseUrl);
WeatherData weather = client.getWeather("London");
assertThat(weather.getCity()).isEqualTo("London");
assertThat(weather.getTemperature()).isEqualTo(15);
wireMock.verify(getRequestedFor(urlEqualTo("/weather?city=London"))
.withHeader("Accept", containing("application/json")));
}
}
```
See `references/advanced-examples.md` for error scenarios, body verification, timeout simulation, and stateful testing.
## Best Practices
- **Dynamic port**: Prevents conflicts in parallel test execution
- **Verify requests**: Ensures correct API usage by the client
- **Test errors**: Cover timeouts, 4xx, 5xx scenarios
- **Focused stubs**: One concern per test
- **Auto-reset**: `@RegisterExtension` resets WireMock between tests
- **Never call real APIs**: Always stub third-party endpoints
## Constraints and Warnings
- **Dynamic ports required**: Fixed ports cause parallel execution conflicts
- **HTTPS testing**: Configure WireMock TLS settings if testing TLS connections
- **Stub precedence**: More specific stubs take priority over general ones
- **Performance**: WireMock adds overhead; mock at client layer for faster tests
- **API changes**: Keep stubs synchronized with actual API contracts
## References
- [WireMock Documentation](https://wiremock.org/)
- [WireMock Stubbing Guide](https://wiremock.org/docs/stubbing/)
- `references/advanced-examples.md` - Error scenarios, body verification, timeouts