unit-test-wiremock-rest-api
Install this skill
npx skills add giuseppe-trisciuoglio/developer-kitWorks across Claude Code, Cursor, Codex, Copilot & Antigravity
This skill facilitates isolated testing of Java-based HTTP clients by substituting live remote web services with local, controlled mock servers. By using the WireMock library, you can intercept outgoing network calls within your JUnit 5 test suite to return predefined responses, such as valid JSON payloads, specific error status codes, or deliberate latency. The implementation centers on the WireMockExtension, which manages the lifecycle of a stubbed server on a dynamic port, ensuring tests remain fast and portable. This approach eliminates external dependencies, bypassing rate limits and network instability during development. It allows for rigorous verification of client-side request construction, header validation, and payload processing, ensuring your integration logic behaves predictably before moving to staging or production environments.
When to Use This Skill
- •Validating client-side parsing of complex JSON third-party responses
- •Ensuring code resilience against upstream service timeouts or service outages
- •Confirming that security tokens or headers are correctly appended to outgoing calls
- •Developing integration logic without requiring access to a sandbox or public API
How to Invoke This Skill
Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:
- “How do I unit test a class that calls an external REST API?
- “Set up WireMock in a JUnit 5 test project
- “Verify my Java client sends the correct headers to an API
- “Simulate a 500 error for a REST API client test
- “Stub a JSON response for a specific API endpoint
Pro Tips
- 💡Organize complex WireMock stubs into separate JSON files or helper methods for better readability and reusability, especially for multi-scenario tests.
- 💡Leverage WireMock's advanced matching capabilities (e.g., regex for URLs, JSONPath for request bodies) to create highly specific and robust stub definitions.
- 💡Integrate WireMock into your build process to ensure all API client logic is thoroughly tested without requiring a running backend service during development or CI/CD.
What this skill does
- •Injects stubbed HTTP responses to mock remote server behavior
- •Verifies that outgoing client requests contain correct headers and bodies
- •Simulates transient errors and HTTP status codes like 404, 500, or 403
- •Uses dynamic port allocation to prevent local environment resource conflicts
- •Integrates directly into JUnit 5 lifecycles via RegisterExtension
When not to use it
- ✕When testing true end-to-end connectivity across actual network infrastructure
- ✕For load testing live services or identifying performance bottlenecks in external APIs
Example workflow
- Add WireMock and JUnit 5 dependencies to your Maven or Gradle build file
- Declare a WireMockExtension field in your test class to manage the server lifecycle
- Define a stub in your test method using stubFor to specify the expected URL and return body
- Initialize your HTTP client with the base URL provided by the WireMock runtime info
- Execute the client method and perform assertions on the returned object
- Call verify to confirm the client sent the expected request to the wiremock server
Prerequisites
- –Basic knowledge of JUnit 5 test annotations
- –Familiarity with Java HTTP client implementation
- –Maven or Gradle project structure
Pitfalls & limitations
- !Hardcoding port numbers instead of using dynamic port assignment causes tests to fail in parallel environments
- !Forgetting to verify specific request attributes can lead to silent failures where the client sends incorrect data
- !Failing to match URL parameters or headers exactly as defined in the test stub causes unexpected 404 results
FAQ
How it compares
While manual mocking requires complex instrumentation of network libraries, WireMock provides a declarative DSL that creates a real HTTP socket, ensuring your actual client code is executed exactly as it would be against a production server.
📄 Full skill instructions — original source: giuseppe-trisciuoglio/developer-kit
Test interactions with third-party REST APIs without making real network calls using WireMock. This skill focuses on pure unit tests (no Spring context) that stub HTTP responses and verify requests.
## When to Use This Skill
Use this skill when:
- Testing services that call external REST APIs
- Need to stub HTTP responses for predictable test behavior
- Want to test error scenarios (timeouts, 500 errors, malformed responses)
- Need to verify request details (headers, query params, request body)
- Integrating with third-party services (payment gateways, weather APIs, etc.)
- Testing without network dependencies or rate limits
- Building unit tests that run fast in CI/CD pipelines
## Core Dependencies
### Maven
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<version>3.4.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>### Gradle
dependencies {
testImplementation("org.wiremock:wiremock:3.4.1")
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.assertj:assertj-core")
}## Basic Pattern: Stubbing and Verifying
### Simple Stub with WireMock Extension
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")));
}
}## Testing Error Scenarios
### Test 4xx and 5xx Responses
@Test
void shouldHandleNotFoundError() {
wireMock.stubFor(get(urlEqualTo("/api/users/999"))
.willReturn(aResponse()
.withStatus(404)
.withBody("{\"error\":\"User not found\"}")));
WeatherApiClient client = new WeatherApiClient(wireMock.getRuntimeInfo().getHttpBaseUrl());
assertThatThrownBy(() -> client.getUser(999))
.isInstanceOf(UserNotFoundException.class)
.hasMessageContaining("User not found");
}
@Test
void shouldRetryOnServerError() {
wireMock.stubFor(get(urlEqualTo("/api/data"))
.willReturn(aResponse()
.withStatus(500)
.withBody("{\"error\":\"Internal server error\"}")));
ApiClient client = new ApiClient(wireMock.getRuntimeInfo().getHttpBaseUrl());
assertThatThrownBy(() -> client.fetchData())
.isInstanceOf(ServerErrorException.class);
}## Request Verification
### Verify Request Details and Payload
@Test
void shouldVerifyRequestBody() {
wireMock.stubFor(post(urlEqualTo("/api/users"))
.willReturn(aResponse()
.withStatus(201)
.withBody("{\"id\":123,\"name\":\"Alice\"}")));
ApiClient client = new ApiClient(wireMock.getRuntimeInfo().getHttpBaseUrl());
UserResponse response = client.createUser("Alice");
assertThat(response.getId()).isEqualTo(123);
wireMock.verify(postRequestedFor(urlEqualTo("/api/users"))
.withRequestBody(matchingJsonPath("$.name", equalTo("Alice")))
.withHeader("Content-Type", containing("application/json")));
}## Best Practices
- **Use dynamic port** to avoid port conflicts in parallel test execution
- **Verify requests** to ensure correct API usage
- **Test error scenarios** thoroughly
- **Keep stubs focused** - one concern per test
- **Reset WireMock** between tests automatically via
@RegisterExtension- **Never call real APIs** - always stub third-party endpoints
## Troubleshooting
**WireMock not intercepting requests**: Ensure your HTTP client uses the stubbed URL from
wireMock.getRuntimeInfo().getHttpBaseUrl().**Port conflicts**: Always use
wireMockConfig().dynamicPort() to let WireMock choose available port.## References
- [WireMock Official Documentation](https://wiremock.org/)
- [WireMock Stubs and Mocking](https://wiremock.org/docs/stubbing/)
- [JUnit 5 Extensions](https://junit.org/junit5/docs/current/user-guide/#extensions)
How to Use This Skill Unit
Option A: Project-Specific (Recommended)
- Click "Download" above
- In your project, create the directory:
.agent/skills/unit-test-wiremock-rest-api/ - Save the file as
SKILL.md - The agent will automatically discover the skill based on its description.
Option B: Global Installation (All Agents)
Save the file to these locations to make it available across all projects:
- Claude Code:
~/.claude/skills/giuseppe-trisciuoglio/developer-kit/unit-test-wiremock-rest-api/SKILL.md - Cursor:
~/.cursor/skills/giuseppe-trisciuoglio/developer-kit/unit-test-wiremock-rest-api/SKILL.md - Antigravity:
~/.gemini/antigravity/skills/giuseppe-trisciuoglio/developer-kit/unit-test-wiremock-rest-api/SKILL.md
🚀 Install with CLI:npx skills add giuseppe-trisciuoglio/developer-kit
