Dr Jskill
jdubois/dr-jskill
Creates Java + Spring Boot projects: Web applications, full-stack apps with Vue.js or Angular or React or vanilla JS, PostgreSQL, REST APIs, and Docker.
Expert guidance for using WireMock in Java applications for HTTP API mocking and testing.
$ npx skills add aehrc/pathling --skill wiremock -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install aehrc/pathling wiremock --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/aehrc/pathling.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/wiremock .claude/skills/wiremock && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "wiremock" agent skill from https://github.com/aehrc/pathling/tree/main/.claude/skills/wiremock into .claude/skills/wiremock/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "wiremock", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/aehrc/pathling/tree/main/.claude/skills/wiremockType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add aehrc/pathling --skill wiremock -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install aehrc/pathling wiremock --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/aehrc/pathling.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/wiremock .agents/skills/wiremock && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "wiremock" agent skill from https://github.com/aehrc/pathling/tree/main/.claude/skills/wiremock into .agents/skills/wiremock/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "wiremock", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add aehrc/pathling --skill wiremock -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install aehrc/pathling wiremock --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/aehrc/pathling.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/wiremock .cursor/skills/wiremock && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "wiremock" agent skill from https://github.com/aehrc/pathling/tree/main/.claude/skills/wiremock into .cursor/skills/wiremock/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "wiremock", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/aehrc/pathling.git --path .claude/skills/wiremock--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add aehrc/pathling --skill wiremock -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install aehrc/pathling wiremock --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/aehrc/pathling.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/wiremock .gemini/skills/wiremock && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "wiremock" agent skill from https://github.com/aehrc/pathling/tree/main/.claude/skills/wiremock into .gemini/skills/wiremock/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "wiremock", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install aehrc/pathling wiremockInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add aehrc/pathling --skill wiremock -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/aehrc/pathling.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/wiremock .github/skills/wiremock && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "wiremock" agent skill from https://github.com/aehrc/pathling/tree/main/.claude/skills/wiremock into .github/skills/wiremock/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "wiremock", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add aehrc/pathling --skill wiremock -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install aehrc/pathling wiremock --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/aehrc/pathling.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/wiremock .opencode/skills/wiremock && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "wiremock" agent skill from https://github.com/aehrc/pathling/tree/main/.claude/skills/wiremock into .opencode/skills/wiremock/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "wiremock", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
wiremockExpert guidance for using WireMock in Java applications for HTTP API mocking and testing.
Wiremock is an agent skill from aehrc/pathling. Expert guidance for using WireMock in Java applications for HTTP API mocking and testing. Use this skill when the user asks to mock HTTP APIs, create API stubs, test REST clients, simulate network faults, verify HTTP requests, or integrate WireMock with Spring Boot. Trigger keywords include "wiremock", "mock http", "stub api", "http mock", "api testing", "rest mock", "simulate fault", "verify request", "spring boot wiremock".
Its SKILL.md is about 5.7k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Backend & APIs, covering REST APIs, Backend development and Third-party API integration. It works with Java and Spring Boot. The repository describes itself as: Tools that make it easier to use FHIR and clinical terminology within data analytics, built on Apache Spark. The licence is Apache-2.0.
2 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 56a3b4a. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are java, json, xml and gradle).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Wiremock loads about 5.7k tokens when it runs. Until then it costs about 110 tokens; SKILL.md has 738 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from aehrc/pathling at commit 56a3b4a, republished under its Apache-2.0 licence (© aehrc). 738 words, ~5,709 tokens.
.claude/skills/wiremock/SKILL.md (or your agent's skills folder).You are an expert in using WireMock for HTTP API mocking in Java applications. You follow best practices for creating reliable, maintainable test mocks.
WireMock enables you to stub HTTP responses for requests matching specific criteria. This allows testing of HTTP clients without depending on external services.
The preferred approaches for configuring stubs are:
mappings directory (for test resources)These methods work well with ephemeral WireMock instances in test contexts, avoiding the need for persistent WireMock servers.
Every stub requires:
import static com.github.tomakehurst.wiremock.client.WireMock.*;
stubFor(get(urlEqualTo("/api/users"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("{\"users\": []}")));WireMock provides convenient methods for common patterns:
stubFor(get("/ping").willReturn(ok()));
stubFor(get("/users").willReturn(okJson("{\"users\": []}")));
stubFor(post("/redirect").willReturn(temporaryRedirect("/new/location")));
stubFor(get("/error").willReturn(serverError()));
stubFor(get("/not-found").willReturn(notFound()));
stubFor(get("/unauthorized").willReturn(unauthorized()));String literal:
.withBody("Hello, world!")JSON object:
.withBody("{\"message\": \"Hello\"}")
// Or use the convenience method:
.willReturn(okJson("{\"message\": \"Hello\"}"))File reference:
.withBodyFile("response.json") // Relative to __files directoryBinary data:
.withBody(binaryData) // Base64-encoded in JSONWhen multiple stubs match a request, priority determines which responds. Lower numbers equal higher priority (1 is highest; default is 5).
stubFor(get(urlEqualTo("/api/users/123"))
.atPriority(1)
.willReturn(aResponse().withStatus(200).withBody("Specific user")));
stubFor(get(urlMatching("/api/users/.*"))
.atPriority(5)
.willReturn(aResponse().withStatus(200).withBody("Any user")));JSON mapping files provide a declarative way to define stubs that can be version-controlled and reused across tests.
Place mapping files in the test resources directory:
src/test/resources/
├── mappings/
│ ├── get-users.json
│ ├── create-user.json
│ └── error-scenarios.json
└── __files/
├── users-response.json
└── user-created-response.json{
"request": {
"method": "GET",
"urlPath": "/api/users"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": "{\"users\": []}"
}
}For larger responses, reference files from the __files directory:
{
"request": {
"method": "GET",
"urlPath": "/api/users"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"bodyFileName": "users-response.json"
}
}URL path with query parameters:
{
"request": {
"method": "GET",
"urlPath": "/api/search",
"queryParameters": {
"q": {
"equalTo": "test"
},
"page": {
"matches": "[0-9]+"
}
}
},
"response": {
"status": 200
}
}Header matching:
{
"request": {
"method": "POST",
"urlPath": "/api/users",
"headers": {
"Content-Type": {
"equalTo": "application/json"
},
"Authorization": {
"matches": "Bearer .*"
}
}
},
"response": {
"status": 201
}
}Request body matching:
{
"request": {
"method": "POST",
"urlPath": "/api/users",
"bodyPatterns": [
{
"matchesJsonPath": "$.name"
},
{
"matchesJsonPath": "$.email",
"equalTo": "user@example.com"
}
]
},
"response": {
"status": 201
}
}{
"priority": 1,
"request": {
"method": "GET",
"urlPath": "/api/users/123"
},
"response": {
"status": 200,
"body": "Specific user"
}
}Spring Boot integration:
@EnableWireMock({
@ConfigureWireMock(
name = "api-service",
filesUnderClasspath = "wiremock"
)
})This loads mappings from src/test/resources/wiremock/mappings/.
Programmatic loading:
WireMockServer wireMockServer = new WireMockServer(
options()
.usingFilesUnderClasspath("wiremock")
.port(8080)
);
wireMockServer.start();JSON mappings provide baseline stubs, while programmatic stubs handle test-specific scenarios:
@Test
void testSpecificScenario() {
// JSON mappings already loaded from src/test/resources/mappings/
// Override or add test-specific stub
stubFor(get("/api/users/999")
.willReturn(notFound()));
// Run test
assertThrows(UserNotFoundException.class, () -> {
apiClient.getUser(999);
});
}Exact URL match (including query parameters):
stubFor(get(urlEqualTo("/api/users?page=1"))
.willReturn(ok()));URL regex:
stubFor(get(urlMatching("/api/users/[0-9]+"))
.willReturn(ok()));Path-only equality (preferred for query parameters):
stubFor(get(urlPathEqualTo("/api/users"))
.willReturn(ok()));Path-only regex:
stubFor(get(urlPathMatching("/api/users/.*"))
.willReturn(ok()));Path templates (RFC 6570 compliant):
stubFor(get(urlPathTemplate("/contacts/{contactId}/addresses/{addressId}"))
.willReturn(ok()));stubFor(get(urlPathEqualTo("/api/users"))
.withQueryParam("page", equalTo("1"))
.withQueryParam("size", matching("[0-9]+"))
.willReturn(ok()));stubFor(get(urlEqualTo("/api/users"))
.withHeader("Accept", equalTo("application/json"))
.withHeader("Authorization", matching("Bearer .*"))
.willReturn(ok()));stubFor(get(urlEqualTo("/api/users"))
.withHeader("X-Custom-Header", absent())
.willReturn(ok()));Exact match:
stubFor(post(urlEqualTo("/api/users"))
.withRequestBody(equalTo("{\"name\": \"John\"}"))
.willReturn(created()));Contains:
stubFor(post(urlEqualTo("/api/users"))
.withRequestBody(containing("John"))
.willReturn(created()));Regex:
stubFor(post(urlEqualTo("/api/users"))
.withRequestBody(matching(".*\"name\"\\s*:\\s*\"[A-Z][a-z]+\".*"))
.willReturn(created()));JSON equality:
stubFor(post(urlEqualTo("/api/users"))
.withRequestBody(equalToJson("{\"name\": \"John\", \"age\": 30}", true, true))
.willReturn(created()));JSON path matching:
stubFor(post(urlEqualTo("/api/users"))
.withRequestBody(matchingJsonPath("$.name"))
.withRequestBody(matchingJsonPath("$.age", equalTo("30")))
.willReturn(created()));JSON schema validation:
stubFor(post(urlEqualTo("/api/users"))
.withRequestBody(matchingJsonSchema(schemaJson))
.willReturn(created()));XML equality:
stubFor(post(urlEqualTo("/api/users"))
.withRequestBody(equalToXml("<user><name>John</name></user>"))
.willReturn(created()));XPath matching:
stubFor(post(urlEqualTo("/api/users"))
.withRequestBody(matchingXPath("//name[text()='John']"))
.willReturn(created()));stubFor(get(urlEqualTo("/api/protected"))
.withBasicAuth("username", "password")
.willReturn(ok()));stubFor(get(urlEqualTo("/api/users"))
.withCookie("session", matching("[A-Z0-9]+"))
.willReturn(ok()));AND combination:
stubFor(post(urlEqualTo("/api/users"))
.withRequestBody(matching("[a-z]+").and(containing("magic")))
.willReturn(ok()));OR combination:
stubFor(get(urlEqualTo("/api/users"))
.withHeader("Accept", matching("application/json").or(matching("application/xml")))
.willReturn(ok()));NOT negation:
stubFor(get(urlEqualTo("/api/users"))
.withHeader("X-Internal", not(matching("true")))
.willReturn(ok()));Add delays to individual stubs:
stubFor(get(urlEqualTo("/api/slow"))
.willReturn(aResponse()
.withStatus(200)
.withFixedDelay(2000))); // 2 second delayLognormal distribution (realistic long-tail latencies):
stubFor(get(urlEqualTo("/api/variable"))
.willReturn(aResponse()
.withStatus(200)
.withLogNormalRandomDelay(90, 0.1))); // Median 90ms, sigma 0.1Uniform distribution (stable latency with jitter):
stubFor(get(urlEqualTo("/api/jitter"))
.willReturn(aResponse()
.withStatus(200)
.withUniformRandomDelay(15, 25))); // Between 15-25msSimulate slow network connections by fragmenting responses:
stubFor(get(urlEqualTo("/api/slow-download"))
.willReturn(aResponse()
.withBody("Large response body...")
.withChunkedDribbleDelay(5, 1000))); // 5 chunks over 1000msSimulate corrupted or failed responses:
import static com.github.tomakehurst.wiremock.http.Fault.*;
stubFor(get(urlEqualTo("/api/fault"))
.willReturn(aResponse().withFault(MALFORMED_RESPONSE_CHUNK)));Available fault types:
EMPTY_RESPONSE: No response dataMALFORMED_RESPONSE_CHUNK: Valid status, then corrupted dataRANDOM_DATA_THEN_CLOSE: Garbage followed by connection closureCONNECTION_RESET_BY_PEER: Immediate disconnectionVerify a request was made:
import static com.github.tomakehurst.wiremock.client.WireMock.*;
verify(getRequestedFor(urlEqualTo("/api/users")));
verify(postRequestedFor(urlEqualTo("/api/users"))
.withHeader("Content-Type", equalTo("application/json")));Verify exact request counts:
verify(exactly(3), postRequestedFor(urlEqualTo("/api/users")));
verify(lessThan(5), getRequestedFor(urlMatching("/api/.*")));
verify(moreThanOrExactly(1), deleteRequestedFor(urlEqualTo("/api/users/123")));Available count operators:
exactly(n)lessThan(n)lessThanOrExactly(n)moreThan(n)moreThanOrExactly(n)List<ServeEvent> allEvents = getAllServeEvents();
List<LoggedRequest> allRequests = findAll(anyRequestedFor(anyUrl()));List<LoggedRequest> userRequests = findAll(
putRequestedFor(urlMatching("/api/users/.*")));List<LoggedRequest> unmatchedRequests = findUnmatchedRequests();Identify stub mappings that almost matched (useful for debugging):
List<NearMiss> nearMisses = findNearMissesForAllUnmatchedRequests();resetAllRequests(); // Clear request log only
reset(); // Clear both stubs and request logAdd the dependency:
Maven:
<dependency>
<groupId>org.wiremock.integrations</groupId>
<artifactId>wiremock-spring-boot</artifactId>
<version>3.10.0</version>
<scope>test</scope>
</dependency>Gradle:
testImplementation 'org.wiremock.integrations:wiremock-spring-boot:3.10.0'import org.springframework.boot.test.context.SpringBootTest;
import org.wiremock.spring.EnableWireMock;
import org.wiremock.spring.ConfigureWireMock;
import org.springframework.beans.factory.annotation.Value;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
@SpringBootTest
@EnableWireMock
class ApiClientTest {
@Value("${wiremock.server.baseUrl}")
private String wireMockUrl;
@Test
void testApiClient() {
stubFor(get("/api/users")
.willReturn(okJson("[{\"id\": 1, \"name\": \"John\"}]")));
// Test your API client
List<User> users = apiClient.getUsers();
assertThat(users).hasSize(1);
verify(getRequestedFor(urlEqualTo("/api/users")));
}
}The integration automatically provides:
wiremock.server.baseUrl — Server base URLwiremock.server.port — HTTP port number@SpringBootTest
@EnableWireMock({
@ConfigureWireMock(
name = "user-service",
port = 8888,
baseUrlProperties = "user-service.url"
)
})
class ApiClientTest {
@Value("${user-service.url}")
private String userServiceUrl;
}Configuration options:
port — HTTP port (default: random)httpsPort — HTTPS port (default: random)name — Instance identifier (default: "wiremock")baseUrlProperties — Custom property name for base URLportProperties — Custom property name for portfilesUnderClasspath — Classpath resource root for mappingsfilesUnderDirectory — Directory root for mappingsimport org.wiremock.spring.InjectWireMock;
import com.github.tomakehurst.wiremock.WireMockServer;
@SpringBootTest
@EnableWireMock
class ApiClientTest {
@InjectWireMock
private WireMockServer wireMock;
@Test
void testWithDirectAccess() {
wireMock.stubFor(get("/api/users").willReturn(ok()));
// Test code
}
}@SpringBootTest
@EnableWireMock({
@ConfigureWireMock(
name = "user-service",
baseUrlProperties = "user-service.url"
),
@ConfigureWireMock(
name = "order-service",
baseUrlProperties = "order-service.url"
)
})
class MultiServiceTest {
@InjectWireMock("user-service")
private WireMockServer userService;
@InjectWireMock("order-service")
private WireMockServer orderService;
@Test
void testMultipleServices() {
userService.stubFor(get("/users/1").willReturn(okJson("{\"id\": 1}")));
orderService.stubFor(get("/orders").willReturn(okJson("[]")));
// Test code that calls both services
}
}For advanced control, implement WireMockConfigurationCustomizer:
import org.wiremock.spring.WireMockConfigurationCustomizer;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
@SpringBootTest
@EnableWireMock({
@ConfigureWireMock(
configurationCustomizers = CustomizerTest.Customizer.class
)
})
class CustomizerTest {
static class Customizer implements WireMockConfigurationCustomizer {
@Override
public void customize(
WireMockConfiguration configuration,
ConfigureWireMock options
) {
configuration
.notifier(new CustomNotifier())
.extensions(new CustomTransformer());
}
}
}List<StubMapping> allStubs = WireMock.listAllStubMappings().getMappings();StubMapping stub = stubFor(get("/api/users").willReturn(ok()));
stub.setResponse(aResponse().withStatus(404));
editStub(stub);// Remove by ID
removeStub(stubId);
// Remove by metadata
removeStubsByMetadata(matchingJsonPath("$.tag", equalTo("temporary")));
// Remove all
WireMock.resetMappings();List<StubMapping> unusedStubs = findUnmatchedStubs();Prefer urlPathEqualTo() over urlEqualTo() when matching query parameters separately to achieve order-invariant matching:
// Good: Order-independent query parameter matching
stubFor(get(urlPathEqualTo("/api/search"))
.withQueryParam("q", equalTo("test"))
.withQueryParam("page", equalTo("1"))
.willReturn(ok()));
// Avoid: Query parameter order matters
stubFor(get(urlEqualTo("/api/search?q=test&page=1"))
.willReturn(ok()));Choose the most specific matcher for your use case:
equalTo() for exact matchesmatching() for regex patternscontaining() for substring checksmatchingJsonPath() for JSON field matchingmatchingJsonSchema() for structural validationUse priority to create layered stub configurations:
Always reset WireMock state between tests:
@BeforeEach
void setUp() {
WireMock.reset(); // Clears both stubs and request log
}Or reset selectively:
@BeforeEach
void setUp() {
WireMock.resetAllRequests(); // Keep stubs, clear request log
}When simulating latency, use lognormal distribution for realistic long-tail behaviour:
stubFor(get("/api/users")
.willReturn(aResponse()
.withStatus(200)
.withLogNormalRandomDelay(100, 0.1)));Always verify that critical requests were made:
@Test
void shouldCreateUser() {
// Stub the response
stubFor(post("/api/users").willReturn(created()));
// Execute test
apiClient.createUser(new User("John"));
// Verify the request
verify(postRequestedFor(urlEqualTo("/api/users"))
.withRequestBody(matchingJsonPath("$.name", equalTo("John"))));
}When using multiple WireMock instances in Spring Boot, use descriptive names:
@EnableWireMock({
@ConfigureWireMock(name = "user-service"),
@ConfigureWireMock(name = "payment-gateway"),
@ConfigureWireMock(name = "notification-service")
})Use JSON mapping files for stubs that are reused across multiple tests:
src/test/resources/mappings/
├── common-success-responses.json
├── common-error-responses.json
└── service-specific/
├── user-service-stubs.json
└── order-service-stubs.jsonReference external files for large response bodies:
{
"request": {
"method": "GET",
"urlPath": "/api/users"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"bodyFileName": "users-response.json"
}
}Reserve programmatic stub creation for test-specific cases that require dynamic behaviour:
@Test
void shouldHandleSpecificEdgeCase() {
// JSON mappings provide baseline stubs
// Add test-specific stub programmatically
stubFor(get("/api/users/edge-case")
.willReturn(aResponse()
.withStatus(200)
.withBody(generateDynamicResponse())));
// Test code
}Always test how your code handles failures:
@Test
void shouldHandleServerError() {
stubFor(get("/api/users").willReturn(serverError()));
assertThrows(ServiceException.class, () -> {
apiClient.getUsers();
});
}
@Test
void shouldHandleTimeout() {
stubFor(get("/api/users")
.willReturn(aResponse()
.withStatus(200)
.withFixedDelay(5000))); // Longer than client timeout
assertThrows(TimeoutException.class, () -> {
apiClient.getUsers();
});
}Simulate stateful interactions using scenarios:
stubFor(post("/api/orders")
.inScenario("Order Flow")
.whenScenarioStateIs(STARTED)
.willReturn(created())
.willSetStateTo("Order Created"));
stubFor(get("/api/orders/123")
.inScenario("Order Flow")
.whenScenarioStateIs("Order Created")
.willReturn(okJson("{\"id\": 123, \"status\": \"PENDING\"}")));Use response templates for dynamic responses (requires extension):
stubFor(get(urlPathMatching("/api/users/([0-9]+)"))
.willReturn(aResponse()
.withBody("{\"id\": {{request.pathSegments.[2]}}, \"name\": \"User\"}")
.withTransformers("response-template")));stubFor(post("/api/users")
.withRequestBody(matchingJsonPath("$.role", equalTo("admin")))
.willReturn(aResponse()
.withStatus(201)
.withBody("{\"role\": \"admin\"}")));
stubFor(post("/api/users")
.withRequestBody(matchingJsonPath("$.role", equalTo("user")))
.willReturn(aResponse()
.withStatus(201)
.withBody("{\"role\": \"user\"}")));stubFor(get("/api/data")
.inScenario("Rate Limit")
.whenScenarioStateIs(STARTED)
.willReturn(ok())
.willSetStateTo("Request 1"));
stubFor(get("/api/data")
.inScenario("Rate Limit")
.whenScenarioStateIs("Request 1")
.willReturn(ok())
.willSetStateTo("Request 2"));
stubFor(get("/api/data")
.inScenario("Rate Limit")
.whenScenarioStateIs("Request 2")
.willReturn(aResponse()
.withStatus(429)
.withHeader("Retry-After", "60")));© aehrc, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/wiremock of aehrc/pathling.
Open the folder on GitHubat commit 56a3b4a
Wiremock next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Wiremock this skillaehrc/pathling | 137 | — | ~5.7k | Automated safety check: Pass | Apache-2.0 | |
| Dr Jskilljdubois/dr-jskill | 342 | — | ~4.6k | Automated safety check: Notes | Apache-2.0 | |
| WxJava Integration Guidebinarywang/WxJava | 33k | — | ~123 | Automated safety check: Pass | Apache-2.0 | |
| Progensivaprasadreddy/sivalabs-agent-skills | 187 | — | ~2.7k | Automated safety check: Notes | MIT | |
| Spring Boot Crud Patternsgiuseppe-trisciuoglio/developer-kit | 355 | — | ~2.5k | Automated safety check: Notes | MIT | |
| Springboot Patternsaffaan-m/ECC | 274k | 5 repos | ~2.5k | Automated safety check: Pass | MIT |
jdubois/dr-jskill
Creates Java + Spring Boot projects: Web applications, full-stack apps with Vue.js or Angular or React or vanilla JS, PostgreSQL, REST APIs, and Docker.
binarywang/WxJava
Plans a WxJava setup for Java, Spring Boot or Solon projects that call WeChat services, from module and BOM choice to config and a minimal working call.
sivaprasadreddy/sivalabs-agent-skills
A skill your agent uses when the user wants to create/generate/scaffold a new Spring Boot project (Maven or Gradle, REST API / Web App / Spring Boot + Angular full stack).
giuseppe-trisciuoglio/developer-kit
Provides and generates complete CRUD workflows for Spring Boot 3 services.
affaan-m/ECC
Spring Boot architecture patterns, REST API design, layered services, data access, caching, async processing, and logging.
Jeffallan/claude-skills
Builds Spring Boot 3.x services with REST controllers, Spring Data JPA, Spring Security 6, WebFlux and Spring Cloud, verified by tests and Actuator health checks.
aehrc/pathling
Expert guidance for implementing FHIR RESTful API servers and clients following the HL7 FHIR specification.
aehrc/pathling
Expert guidance for implementing FHIR Bulk Data Access (Flat FHIR) following the HL7 specification.
aehrc/pathling
Expert guidance for using the Databricks CLI to manage Databricks workspaces, clusters, jobs, pipelines, Unity Catalog, SQL warehouses, serving endpoints, secrets, bundles, and all other Databricks…
aehrc/pathling
FHIR RESTful search specification expert with access to the official HL7 search specification text and the formal SearchParameter registry.
aehrc/pathling
Design and generate comprehensive FHIRPath test suites using input domain partitioning and Pathling's DSL test framework.
aehrc/pathling
Expert guidance for implementing FHIR servers using HAPI FHIR Plain Server framework.
Works with
Categories
Expert guidance for using WireMock in Java applications for HTTP API mocking and testing. Wiremock is an agent skill from aehrc/pathling. Expert guidance for using WireMock in Java applications for HTTP API mocking and testing.
Wiremock fits situations like: the user asks to mock HTTP APIs; create API stubs; test REST clients; simulate network faults.
Run `npx skills add aehrc/pathling --skill wiremock -a claude-code`. Or copy the skill folder (.claude/skills/wiremock in aehrc/pathling) into .claude/skills/wiremock in your project. Claude Code loads it when a task matches its description.
Run `npx skills add aehrc/pathling --skill wiremock -a codex`. Or copy the skill folder (.claude/skills/wiremock in aehrc/pathling) into .agents/skills/wiremock in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add aehrc/pathling --skill wiremock -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/wiremock, .gemini/skills/wiremock, .github/skills/wiremock and .opencode/skills/wiremock in your project.
SKILL.md names no scripts, command-line tools or credentials: Wiremock is instructions for the agent only.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Wiremock is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 5.7k tokens (SKILL.md is roughly 23k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Wiremock: Dr Jskill (jdubois/dr-jskill, 342 stars), WxJava Integration Guide (binarywang/WxJava, 33k stars), Progen (sivaprasadreddy/sivalabs-agent-skills, 187 stars) and Spring Boot Crud Patterns (giuseppe-trisciuoglio/developer-kit, 355 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
aehrc (a GitHub organization) maintains it in aehrc/pathling, which has 137 GitHub stars. The repository holds 25 skills in this directory. The repository was last updated on October 7, 2026.
Source: aehrc/pathling on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.