|
对于最新稳定版本,请使用 Spring Framework 7.0.6! |
测试客户端应用程序
你可以使用客户端测试来测试内部使用 RestTemplate 的代码。
其核心思想是声明预期的请求并提供“桩”(stub)响应,
从而让你能够专注于隔离测试代码(即无需启动服务器)。
以下示例展示了如何实现这一点:
-
Java
-
Kotlin
RestTemplate restTemplate = new RestTemplate();
MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build();
mockServer.expect(requestTo("/greeting")).andRespond(withSuccess());
// Test code that uses the above RestTemplate ...
mockServer.verify();
val restTemplate = RestTemplate()
val mockServer = MockRestServiceServer.bindTo(restTemplate).build()
mockServer.expect(requestTo("/greeting")).andRespond(withSuccess())
// Test code that uses the above RestTemplate ...
mockServer.verify()
在前面的示例中,MockRestServiceServer(用于客户端 REST 测试的核心类)通过一个自定义的 RestTemplate 对 ClientHttpRequestFactory 进行配置,该工厂会将实际请求与预期进行比对,并返回“模拟”(stub)响应。在此例中,我们期望收到一个发往 /greeting 的请求,并希望返回一个状态码为 200、内容类型为 text/plain 的响应。我们可以根据需要定义更多预期的请求和模拟响应。在定义好这些预期请求和模拟响应之后,RestTemplate 在客户端代码中可以像平常一样使用。测试结束时,可以调用 mockServer.verify() 来验证所有预期是否都已满足。
默认情况下,请求应按照声明期望的顺序到达。你可以在构建服务器时设置 ignoreExpectOrder 选项,这样系统会按顺序检查所有期望,以找到与给定请求匹配的项。这意味着请求可以以任意顺序到达。以下示例使用了 ignoreExpectOrder:
-
Java
-
Kotlin
server = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();
server = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build()
即使默认情况下请求是无序的,每个请求也只允许执行一次。
expect 方法提供了一个重载变体,该变体接受一个 ExpectedCount 参数,
用于指定调用次数的范围(例如 once、manyTimes、max、min、
between 等)。以下示例使用了 times:
-
Java
-
Kotlin
RestTemplate restTemplate = new RestTemplate();
MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build();
mockServer.expect(times(2), requestTo("/something")).andRespond(withSuccess());
mockServer.expect(times(3), requestTo("/somewhere")).andRespond(withSuccess());
// ...
mockServer.verify();
val restTemplate = RestTemplate()
val mockServer = MockRestServiceServer.bindTo(restTemplate).build()
mockServer.expect(times(2), requestTo("/something")).andRespond(withSuccess())
mockServer.expect(times(3), requestTo("/somewhere")).andRespond(withSuccess())
// ...
mockServer.verify()
请注意,当未设置 ignoreExpectOrder(默认情况)时,请求将按照声明的顺序进行匹配,但该顺序仅适用于每个预期请求的第一次出现。例如,如果先预期两次对 "/something" 的请求,然后预期三次对 "/somewhere" 的请求,那么在任何对 "/somewhere" 的请求之前,必须先有一次对 "/something" 的请求;除此之外,后续的 "/something" 和 "/somewhere" 请求可以在任意时间发生。
作为上述所有方法的替代方案,客户端测试支持还提供了一个 ClientHttpRequestFactory 实现,你可以将其配置到 RestTemplate 中,
从而将其绑定到一个 MockMvc 实例。这样可以在不启动服务器的情况下,使用实际的服务器端逻辑来处理请求。以下示例展示了如何实现这一点:
-
Java
-
Kotlin
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
this.restTemplate = new RestTemplate(new MockMvcClientHttpRequestFactory(mockMvc));
// Test code that uses the above RestTemplate ...
val mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build()
restTemplate = RestTemplate(MockMvcClientHttpRequestFactory(mockMvc))
// Test code that uses the above RestTemplate ...
在某些情况下,可能需要实际调用远程服务,而不是模拟响应。以下示例展示了如何通过 ExecutingResponseCreator 来实现这一点:
-
Java
-
Kotlin
RestTemplate restTemplate = new RestTemplate();
// Create ExecutingResponseCreator with the original request factory
ExecutingResponseCreator withActualResponse = new ExecutingResponseCreator(restTemplate.getRequestFactory());
MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build();
mockServer.expect(requestTo("/profile")).andRespond(withSuccess());
mockServer.expect(requestTo("/quoteOfTheDay")).andRespond(withActualResponse);
// Test code that uses the above RestTemplate ...
mockServer.verify();
val restTemplate = RestTemplate()
// Create ExecutingResponseCreator with the original request factory
val withActualResponse = new ExecutingResponseCreator(restTemplate.getRequestFactory())
val mockServer = MockRestServiceServer.bindTo(restTemplate).build()
mockServer.expect(requestTo("/profile")).andRespond(withSuccess())
mockServer.expect(requestTo("/quoteOfTheDay")).andRespond(withActualResponse)
// Test code that uses the above RestTemplate ...
mockServer.verify()
在前面的示例中,我们在 ExecutingResponseCreator 将 ClientHttpRequestFactory 的 RestTemplate 替换为另一个用于模拟响应的工厂 之前,先使用该 MockRestServiceServer 创建了 4。
然后,我们通过两种类型的响应来定义预期行为:
-
针对
200端点的一个存根/profile响应(不会执行实际的请求) -
通过调用
/quoteOfTheDay端点获得的响应
在第二种情况下,请求通过之前捕获的 ClientHttpRequestFactory 执行。这会生成一个响应,该响应可能来自实际的远程服务器,具体取决于 RestTemplate 最初是如何配置的。
静态导入
与服务端测试类似,客户端测试的流式 API 需要导入一些静态方法。这些静态导入很容易通过搜索 MockRest* 找到。Eclipse 用户应在 Eclipse 的偏好设置中(路径为 Java → Editor → Content Assist → Favorites)将 MockRestRequestMatchers.* 和 MockRestResponseCreators.* 添加为“收藏的静态成员”。这样,在输入静态方法名的第一个字符后,即可使用内容辅助功能。其他 IDE(例如 IntelliJ)可能无需任何额外配置。请查阅相关 IDE 对静态成员代码补全的支持情况。
客户端 REST 测试的更多示例
Spring MVC Test 自身的测试包含客户端 REST 测试的示例。