2. Maven 依赖
要在项目中使用 WireMock,需要在 POM 文件中添加以下依赖:
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<version>3.3.1</version>
<scope>test</scope>
</dependency>
3. 手动管理服务器
本节介绍如何手动配置 WireMock 服务器(不依赖 JUnit 自动配置),通过一个简单存根演示基本用法。
3.1. 服务器设置
首先创建 WireMock 服务器实例:
WireMockServer wireMockServer = new WireMockServer(String host, int port);
若不提供参数:
- 主机默认为
localhost
- 端口默认为
8080
通过以下方法控制服务器生命周期:
wireMockServer.start(); // 启动服务器
wireMockServer.stop(); // 停止服务器
3.2. 基础用法
演示一个最简单的存根配置(精确匹配 URL):
创建服务器实例:
WireMockServer wireMockServer = new WireMockServer();
启动服务器(客户端连接前必须启动):
wireMockServer.start();
配置存根:
configureFor("localhost", 8080); stubFor(get(urlEqualTo("/baeldung")) .willReturn(aResponse() .withBody("Welcome to Baeldung!")));
创建 HTTP 客户端(使用 Apache HttpClient):
CloseableHttpClient httpClient = HttpClients.createDefault();
执行请求并获取响应:
HttpGet request = new HttpGet("http://localhost:8080/baeldung"); HttpResponse httpResponse = httpClient.execute(request);
响应体转字符串(辅助方法):
String responseString = convertResponseToString(httpResponse);
辅助方法实现:
private String convertResponseToString(HttpResponse response) throws IOException { InputStream responseStream = response.getEntity().getContent(); Scanner scanner = new Scanner(responseStream, "UTF-8"); String responseString = scanner.useDelimiter("\\Z").next(); scanner.close(); return responseString; }
验证行为:
verify(getRequestedFor(urlEqualTo("/baeldung"))); // 验证请求URL assertEquals("Welcome to Baeldung!", responseString); // 验证响应体
释放资源:
wireMockServer.stop();
4. JUnit 管理服务器
本节展示如何使用 JUnit Rule 自动管理 WireMock 服务器生命周期。
4.1. 服务器设置
通过 @Rule
注解集成 JUnit:
- JUnit 自动在测试方法前启动服务器,方法后停止服务器
- 可指定端口(未指定时默认
8080
)
@Rule
public WireMockRule wireMockRule = new WireMockRule(int port);
提示:可通过
Options
接口配置主机(默认localhost
)等参数。
4.2. URL 匹配
使用正则表达式匹配接口路径:
配置存根:
stubFor(get(urlPathMatching("/baeldung/.*")) .willReturn(aResponse() .withStatus(200) .withHeader("Content-Type", "application/json") .withBody("\"testing-library\": \"WireMock\"")));
执行请求:
CloseableHttpClient httpClient = HttpClients.createDefault(); HttpGet request = new HttpGet("http://localhost:8080/baeldung/wiremock"); HttpResponse httpResponse = httpClient.execute(request); String stringResponse = convertHttpResponseToString(httpResponse);
辅助方法:
private String convertHttpResponseToString(HttpResponse httpResponse) throws IOException { InputStream inputStream = httpResponse.getEntity().getContent(); return convertInputStreamToString(inputStream); } private String convertInputStreamToString(InputStream inputStream) { Scanner scanner = new Scanner(inputStream, "UTF-8"); String string = scanner.useDelimiter("\\Z").next(); scanner.close(); return string; }
验证结果:
verify(getRequestedFor(urlEqualTo("/baeldung/wiremock"))); assertEquals(200, httpResponse.getStatusLine().getStatusCode()); assertEquals("application/json", httpResponse.getFirstHeader("Content-Type").getValue()); assertEquals("\"testing-library\": \"WireMock\"", stringResponse);
4.3. 请求头匹配
演示基于请求头的存根配置:
配置存根(匹配
Accept
头):stubFor(get(urlPathEqualTo("/baeldung/wiremock")) .withHeader("Accept", matching("text/.*")) .willReturn(aResponse() .withStatus(503) .withHeader("Content-Type", "text/html") .withBody("!!! Service Unavailable !!!")));
执行请求(添加请求头):
CloseableHttpClient httpClient = HttpClients.createDefault(); HttpGet request = new HttpGet("http://localhost:8080/baeldung/wiremock"); request.addHeader("Accept", "text/html"); HttpResponse httpResponse = httpClient.execute(request); String stringResponse = convertHttpResponseToString(httpResponse);
验证结果:
verify(getRequestedFor(urlEqualTo("/baeldung/wiremock"))); assertEquals(503, httpResponse.getStatusLine().getStatusCode()); assertEquals("text/html", httpResponse.getFirstHeader("Content-Type").getValue()); assertEquals("!!! Service Unavailable !!!", stringResponse);
4.4. 请求体匹配
演示基于请求体的存根配置:
配置存根(匹配 JSON 请求体):
stubFor(post(urlEqualTo("/baeldung/wiremock")) .withHeader("Content-Type", equalTo("application/json")) .withRequestBody(containing("\"testing-library\": \"WireMock\"")) .withRequestBody(containing("\"creator\": \"Tom Akehurst\"")) .withRequestBody(containing("\"website\": \"wiremock.org\"")) .willReturn(aResponse() .withStatus(200)));
准备请求体(从 classpath 加载 JSON):
InputStream jsonInputStream = this.getClass().getClassLoader().getResourceAsStream("wiremock_intro.json"); String jsonString = convertInputStreamToString(jsonInputStream); StringEntity entity = new StringEntity(jsonString);
wiremock_intro.json
内容:{ "testing-library": "WireMock", "creator": "Tom Akehurst", "website": "wiremock.org" }
执行请求:
CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost request = new HttpPost("http://localhost:8080/baeldung/wiremock"); request.addHeader("Content-Type", "application/json"); request.setEntity(entity); HttpResponse response = httpClient.execute(request);
验证结果:
verify(postRequestedFor(urlEqualTo("/baeldung/wiremock")) .withHeader("Content-Type", equalTo("application/json"))); assertEquals(200, response.getStatusLine().getStatusCode());
4.5. 存根优先级
处理多个存根匹配同一请求的场景:
踩坑提示:默认情况下,最近添加的存根优先级最高。可通过
atPriority()
覆盖此行为(数值越小优先级越高)。
场景一:未设置优先级
配置两个存根:
stubFor(get(urlPathMatching("/baeldung/.*")) .willReturn(aResponse().withStatus(200))); stubFor(get(urlPathEqualTo("/baeldung/wiremock")) .withHeader("Accept", matching("text/.*")) .willReturn(aResponse().withStatus(503)));
执行请求(使用辅助方法):
HttpResponse httpResponse = generateClientAndReceiveResponseForPriorityTests();
辅助方法:
private HttpResponse generateClientAndReceiveResponseForPriorityTests() throws IOException { CloseableHttpClient httpClient = HttpClients.createDefault(); HttpGet request = new HttpGet("http://localhost:8080/baeldung/wiremock"); request.addHeader("Accept", "text/xml"); return httpClient.execute(request); }
验证结果(后配置的存根生效):
verify(getRequestedFor(urlEqualTo("/baeldung/wiremock"))); assertEquals(503, httpResponse.getStatusLine().getStatusCode());
场景二:设置优先级
配置带优先级的存根:
stubFor(get(urlPathMatching("/baeldung/.*")) .atPriority(1) // 高优先级 .willReturn(aResponse().withStatus(200))); stubFor(get(urlPathEqualTo("/baeldung/wiremock")) .atPriority(2) // 低优先级 .withHeader("Accept", matching("text/.*")) .willReturn(aResponse().withStatus(503)));
执行请求(同场景一):
HttpResponse httpResponse = generateClientAndReceiveResponseForPriorityTests();
验证结果(高优先级存根生效):
verify(getRequestedFor(urlEqualTo("/baeldung/wiremock"))); assertEquals(200, httpResponse.getStatusLine().getStatusCode());
5. 总结
本文介绍了 WireMock 的核心功能,包括:
- 手动/JUnit 两种服务器管理方式
- URL/请求头/请求体匹配技巧
- 存根优先级控制机制
通过这些技术,可以高效构建 REST API 测试的模拟服务。完整示例代码可在 GitHub 项目 中获取。