Testing Client Applications

可以使用客户端测试来测试内部使用 RestTemplate 的代码。其想法是声明预期请求,并提供“桩”响应,以便能够专注于孤立地测试代码(即,在不运行服务器的情况下)。以下示例展示了如何执行此操作:

  • 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 测试的中心类)使用自定义 ClientHttpRequestFactory 配置 RestTemplate,该 Factory 断言实际请求与预期相符,并返回“桩”响应。在这种情况下,我们希望对 /greeting 发出请求,并希望返回具有 text/plain 内容的 200 响应。我们可以根据需要定义其他预期请求和桩响应。当我们定义预期请求和桩响应时,RestTemplate 可以像通常一样用于客户端代码。在测试结束时,可以使用 mockServer.verify() 验证是否已满足所有预期。 默认情况下,会按声明预期的顺序期待请求。可以在构建服务器时设置 ignoreExpectOrder 选项,在这种情况下,将按顺序检查所有预期以查找给定请求的匹配项。这意味着允许请求按任何顺序进入。下面的示例使用了 ignoreExpectOrder

  • Java

  • Kotlin

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

即使在默认情况下以无序请求,每个请求也仅允许运行一次。expect 方法提供一个重载变体,它接受一个指定计数范围的 ExpectedCount 参数(例如,oncemanyTimesmaxminbetween 等)。以下示例使用了 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()

在上面的示例中,我们在 MockRestServiceServerRestTemplate 中的 ClientHttpRequestFactory 替换为模拟响应的不同 Factory 之前 使用此 Factory 创建 ExecutingResponseCreator。然后,我们使用两种类型的响应定义预期:

  • 针对 /profile 终结点的一个桩 200 响应(不会执行实际请求)

  • 通过调用 /quoteOfTheDay 终结点而获得的响应

在第二种情况下,通过之前捕获的 ClientHttpRequestFactory 执行请求。根据 RestTemplate 的原始配置,这会生成一个响应,例如该响应可能来自实际的远程服务器。

Static Imports

与服务器端测试一样,用于客户端测试的 fluent API 需要一些静态导入。可以通过搜索 MockRest* 来轻松找到这些导入。Eclipse 用户应在 Java → 编辑器 → 内容辅助 → 偏好设置下的 Eclipse 偏好设置中将 MockRestRequestMatchers.MockRestResponseCreators. 添加为 “最喜欢的静态成员”。这允许在键入静态方法名称的第一个字符后使用内容辅助。其他 IDE(如 IntelliJ)可能不需要任何其他配置。检查静态成员上的代码完成支持。

Further Examples of Client-side REST Tests

Spring MVC 测试自己的测试包括 示例测试 客户端端 REST 测试。