测试客户端应用程序

您可以使用客户端测试来测试内部使用RestTemplate的代码。其思想是声明预期请求并提供“存根”响应,以便您可以专注于独立测试代码(即在不运行服务器的情况下)。以下示例展示了如何实现:

  • Java

  • Kotlin

RestTemplate restTemplate = new RestTemplate();

MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build();
mockServer.expect(requestTo("/greeting")).andRespond(withSuccess());

// 测试使用上述RestTemplate的代码...

mockServer.verify();
val restTemplate = RestTemplate()

val mockServer = MockRestServiceServer.bindTo(restTemplate).build()
mockServer.expect(requestTo("/greeting")).andRespond(withSuccess())

// 测试使用上述RestTemplate的代码...

mockServer.verify()

在上面的示例中,MockRestServiceServer(用于客户端REST测试的中心类)使用自定义的ClientHttpRequestFactory配置RestTemplate,该工厂会根据预期断言实际请求并返回“存根”响应。在这种情况下,我们期望请求到/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));

// 测试使用上述RestTemplate的代码...
val mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build()
restTemplate = RestTemplate(MockMvcClientHttpRequestFactory(mockMvc))

// 测试使用上述RestTemplate的代码...

在某些情况下,可能需要执行对远程服务的实际调用,而不是模拟响应。以下示例展示了如何通过ExecutingResponseCreator实现:

  • Java

  • Kotlin

RestTemplate restTemplate = new RestTemplate();

// 使用原始请求工厂创建ExecutingResponseCreator
ExecutingResponseCreator withActualResponse = new ExecutingResponseCreator(restTemplate.getRequestFactory());

MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build();
mockServer.expect(requestTo("/profile")).andRespond(withSuccess());
mockServer.expect(requestTo("/quoteOfTheDay")).andRespond(withActualResponse);

// 测试使用上述RestTemplate的代码...

mockServer.verify();
val restTemplate = RestTemplate()

// 使用原始请求工厂创建ExecutingResponseCreator
val withActualResponse = new ExecutingResponseCreator(restTemplate.getRequestFactory())

val mockServer = MockRestServiceServer.bindTo(restTemplate).build()
mockServer.expect(requestTo("/profile")).andRespond(withSuccess())
mockServer.expect(requestTo("/quoteOfTheDay")).andRespond(withActualResponse)

// 测试使用上述RestTemplate的代码...

mockServer.verify()

在上面的示例中,我们在MockRestServiceServer用不同的工厂模拟响应之前,使用RestTemplateClientHttpRequestFactory创建了ExecutingResponseCreator。然后我们定义了两种响应的预期:

  • /profile端点创建一个存根200响应(不会执行实际请求)

  • 通过调用/quoteOfTheDay端点获取的响应

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

静态导入

与服务器端测试一样,客户端测试的流畅API需要一些静态导入。通过搜索MockRest*可以轻松找到它们。Eclipse用户应该在Eclipse首选项中的Java → Editor → Content Assist → Favorites下将MockRestRequestMatchers.*MockRestResponseCreators.*添加为“喜爱的静态成员”。这样在输入静态方法名的第一个字符后,就可以使用内容辅助。其他IDE(如IntelliJ)可能不需要任何额外配置。检查对静态成员的代码完成支持。

客户端REST测试的进一步示例

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