跳到主要内容

测试客户端应用程序

ChatGPT-4o-mini 中英对照 Testing Client Applications

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

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

在前面的示例中,MockRestServiceServer(客户端 REST 测试的核心类)使用自定义的 ClientHttpRequestFactory 配置 RestTemplate,该工厂将实际请求与预期进行比较,并返回“存根”响应。在这种情况下,我们期望请求 /greeting 并希望返回一个 200 响应,内容为 text/plain。我们可以根据需要定义额外的预期请求和存根响应。当我们定义预期请求和存根响应时,RestTemplate 可以像往常一样在客户端代码中使用。在测试结束时,可以使用 mockServer.verify() 来验证所有预期是否已满足。

默认情况下,请求的顺序是按照期望声明的顺序进行的。您可以在构建服务器时设置 ignoreExpectOrder 选项,在这种情况下,所有期望都会被检查(按顺序)以找到与给定请求匹配的期望。这意味着请求可以以任何顺序到达。以下示例使用了 ignoreExpectOrder

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

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

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

注意,当 ignoreExpectOrder 未设置(默认情况下),因此请求按声明顺序预期时,该顺序仅适用于任何预期请求的第一个。例如,如果 "/something" 预期两次,随后是 "/somewhere" 三次,那么在请求 "/somewhere" 之前应该有对 "/something" 的请求,但除此之外,后续的 "/something" 和 "/somewhere" 请求可以在任何时间到达。

作为上述所有内容的替代,客户端测试支持还提供了一个 ClientHttpRequestFactory 实现,您可以将其配置到 RestTemplate 中,以将其绑定到 MockMvc 实例。这允许使用实际的服务器端逻辑处理请求,但无需运行服务器。以下示例展示了如何做到这一点:

MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
this.restTemplate = new RestTemplate(new MockMvcClientHttpRequestFactory(mockMvc));

// Test code that uses the above RestTemplate ...
java

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

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

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

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

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

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

静态导入

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

客户端 REST 测试的更多示例

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