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
参数(例如,once
、manyTimes
、max
、min
、between
等)。以下示例使用了 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()
在上面的示例中,我们在 MockRestServiceServer
将 RestTemplate
中的 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.