对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

测试客户端应用程序

你可以使用客户端测试来测试内部使用 RestTemplate 的代码。 其核心思想是声明预期的请求并提供“桩”(stub)响应, 从而让你能够专注于隔离测试代码(即无需启动服务器)。 以下示例展示了如何实现这一点:spring-doc.cadn.net.cn

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 测试的核心类)通过一个自定义的 RestTemplateClientHttpRequestFactory 进行配置,该工厂会将实际请求与预期进行比对,并返回“模拟”(stub)响应。在此例中,我们期望收到一个发往 /greeting 的请求,并希望返回一个状态码为 200、内容类型为 text/plain 的响应。我们可以根据需要定义更多预期的请求和模拟响应。在定义好这些预期请求和模拟响应之后,RestTemplate 在客户端代码中可以像平常一样使用。测试结束时,可以调用 mockServer.verify() 来验证所有预期是否都已满足。spring-doc.cadn.net.cn

默认情况下,请求应按照声明期望的顺序到达。你可以在构建服务器时设置 ignoreExpectOrder 选项,这样系统会按顺序检查所有期望,以找到与给定请求匹配的项。这意味着请求可以以任意顺序到达。以下示例使用了 ignoreExpectOrderspring-doc.cadn.net.cn

server = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();
server = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build()

即使默认情况下请求是无序的,每个请求也只允许执行一次。 expect 方法提供了一个重载变体,该变体接受一个 ExpectedCount 参数, 用于指定调用次数的范围(例如 oncemanyTimesmaxminbetween 等)。以下示例使用了 timesspring-doc.cadn.net.cn

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" 请求可以在任意时间发生。spring-doc.cadn.net.cn

作为上述所有方法的替代方案,客户端测试支持还提供了一个 ClientHttpRequestFactory 实现,你可以将其配置到 RestTemplate 中, 从而将其绑定到一个 MockMvc 实例。这样可以在不启动服务器的情况下,使用实际的服务器端逻辑来处理请求。以下示例展示了如何实现这一点:spring-doc.cadn.net.cn

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 来实现这一点:spring-doc.cadn.net.cn

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()

在前面的示例中,我们在 ExecutingResponseCreatorClientHttpRequestFactoryRestTemplate 替换为另一个用于模拟响应的工厂 之前,先使用该 MockRestServiceServer 创建了 4。 然后,我们通过两种类型的响应来定义预期行为:spring-doc.cadn.net.cn

在第二种情况下,请求通过之前捕获的 ClientHttpRequestFactory 执行。这会生成一个响应,该响应可能来自实际的远程服务器,具体取决于 RestTemplate 最初是如何配置的。spring-doc.cadn.net.cn

静态导入

与服务端测试类似,客户端测试的流式 API 需要导入一些静态方法。这些静态导入很容易通过搜索 MockRest* 找到。Eclipse 用户应在 Eclipse 的偏好设置中(路径为 Java → Editor → Content Assist → Favorites)将 MockRestRequestMatchers.*MockRestResponseCreators.* 添加为“收藏的静态成员”。这样,在输入静态方法名的第一个字符后,即可使用内容辅助功能。其他 IDE(例如 IntelliJ)可能无需任何额外配置。请查阅相关 IDE 对静态成员代码补全的支持情况。spring-doc.cadn.net.cn

客户端 REST 测试的更多示例

Spring MVC Test 自身的测试包含客户端 REST 测试的示例spring-doc.cadn.net.cn