测试客户端应用程序

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

  • Java

RestTemplate restTemplate = new RestTemplate();

MockRestServiceServer 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

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

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

  • Java

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

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

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

  • Java

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

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

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

  • Java

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

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

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

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

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

静态导入

与服务器端测试一样,客户端测试的流式 API 需要一些静态导入。搜索 MockRest* 很容易找到这些导入。Eclipse 用户应将 MockRestRequestMatchers.*MockRestResponseCreators.* 添加为 Eclipse 首选项中 Java → Editor → Content Assist → Favorites 下的“favorite static members”。这允许在键入静态方法名称的第一个字符后使用内容辅助。其他 IDE(如 IntelliJ)可能不需要任何其他配置。检查对静态成员的代码完成支持。

客户端 REST 测试的更多示例

Web MVC Test 自身的测试包括客户端 REST 测试的 示例测试