Testing Client Applications

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

You can use client-side tests to test code that internally uses the RestTemplate. The idea is to declare expected requests and to provide “stub” responses so that you can focus on testing the code in isolation (that is, without running a server). The following example shows how to do so:

  • 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() 验证是否已满足所有预期。

In the preceding example, MockRestServiceServer (the central class for client-side REST tests) configures the RestTemplate with a custom ClientHttpRequestFactory that asserts actual requests against expectations and returns “stub” responses. In this case, we expect a request to /greeting and want to return a 200 response with text/plain content. We can define additional expected requests and stub responses as needed. When we define expected requests and stub responses, the RestTemplate can be used in client-side code as usual. At the end of testing, mockServer.verify() can be used to verify that all expectations have been satisfied.

默认情况下,会按声明预期的顺序期待请求。可以在构建服务器时设置 ignoreExpectOrder 选项,在这种情况下,将按顺序检查所有预期以查找给定请求的匹配项。这意味着允许请求按任何顺序进入。下面的示例使用了 ignoreExpectOrder

By default, requests are expected in the order in which expectations were declared. You can set the ignoreExpectOrder option when building the server, in which case all expectations are checked (in order) to find a match for a given request. That means requests are allowed to come in any order. The following example uses ignoreExpectOrder:

  • Java

  • Kotlin

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

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

Even with unordered requests by default, each request is allowed to run once only. The expect method provides an overloaded variant that accepts an ExpectedCount argument that specifies a count range (for example, once, manyTimes, max, min, between, and so on). The following example uses 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”,请求可以在任何时候进入。

Note that, when ignoreExpectOrder is not set (the default), and, therefore, requests are expected in order of declaration, then that order applies only to the first of any expected request. For example if "/something" is expected two times followed by "/somewhere" three times, then there should be a request to "/something" before there is a request to "/somewhere", but, aside from that subsequent "/something" and "/somewhere", requests can come at any time.

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

As an alternative to all of the above, the client-side test support also provides a ClientHttpRequestFactory implementation that you can configure into a RestTemplate to bind it to a MockMvc instance. That allows processing requests using actual server-side logic but without running a server. The following example shows how to do so:

  • 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 执行此操作:

In some cases it may be necessary to perform an actual call to a remote service instead of mocking the response. The following example shows how to do that through 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。然后,我们使用两种类型的响应定义预期:

In the preceding example, we create the ExecutingResponseCreator using the ClientHttpRequestFactory from the RestTemplate before MockRestServiceServer replaces it with a different one that mocks responses. Then we define expectations with two kinds of responses:

  • a stub 200 response for the /profile endpoint (no actual request will be executed)

  • a response obtained through a call to the /quoteOfTheDay endpoint

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

In the second case, the request is executed through the ClientHttpRequestFactory that was captured earlier. This generates a response that could e.g. come from an actual remote server, depending on how the RestTemplate was originally configured.

Static Imports

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

As with server-side tests, the fluent API for client-side tests requires a few static imports. Those are easy to find by searching for MockRest*. Eclipse users should add MockRestRequestMatchers. and MockRestResponseCreators. as “favorite static members” in the Eclipse preferences under Java → Editor → Content Assist → Favorites. That allows using content assist after typing the first character of the static method name. Other IDEs (such IntelliJ) may not require any additional configuration. Check for the support for code completion on static members.

Further Examples of Client-side REST Tests

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

Spring MVC Test’s own tests include example tests of client-side REST tests.