Merge branch '5.1.x'
This commit is contained in:
commit
97d020c509
|
@ -463,9 +463,15 @@ class DefaultWebClient implements WebClient {
|
||||||
for (StatusHandler handler : this.statusHandlers) {
|
for (StatusHandler handler : this.statusHandlers) {
|
||||||
if (handler.test(response.statusCode())) {
|
if (handler.test(response.statusCode())) {
|
||||||
HttpRequest request = this.requestSupplier.get();
|
HttpRequest request = this.requestSupplier.get();
|
||||||
Mono<? extends Throwable> exMono = handler.apply(response, request);
|
Mono<? extends Throwable> exMono;
|
||||||
exMono = exMono.flatMap(ex -> drainBody(response, ex));
|
try {
|
||||||
exMono = exMono.onErrorResume(ex -> drainBody(response, ex));
|
exMono = handler.apply(response, request);
|
||||||
|
exMono = exMono.flatMap(ex -> drainBody(response, ex));
|
||||||
|
exMono = exMono.onErrorResume(ex -> drainBody(response, ex));
|
||||||
|
}
|
||||||
|
catch (Throwable ex2) {
|
||||||
|
exMono = drainBody(response, ex2);
|
||||||
|
}
|
||||||
T result = errorFunction.apply(exMono);
|
T result = errorFunction.apply(exMono);
|
||||||
return insertCheckpoint(result, response.statusCode(), request);
|
return insertCheckpoint(result, response.statusCode(), request);
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,15 @@ public class WebClientDataBufferAllocatingTests extends AbstractDataBufferAlloca
|
||||||
testOnStatus(ex, response -> response.bodyToMono(Void.class).then(Mono.error(ex)));
|
testOnStatus(ex, response -> response.bodyToMono(Void.class).then(Mono.error(ex)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // gh-23230
|
||||||
|
public void onStatusWithImmediateErrorAndBodyNotConsumed() {
|
||||||
|
RuntimeException ex = new RuntimeException("response error");
|
||||||
|
testOnStatus(ex, response -> {
|
||||||
|
throw ex;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void testOnStatus(Throwable expected,
|
private void testOnStatus(Throwable expected,
|
||||||
Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction) {
|
Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction) {
|
||||||
|
|
||||||
|
|
|
@ -5079,20 +5079,43 @@ resulting links by using XPath expressions:
|
||||||
.andExpect(xpath("/person/ns:link[@rel='self']/@href", ns).string("http://localhost:8080/people"));
|
.andExpect(xpath("/person/ns:link[@rel='self']/@href", ns).string("http://localhost:8080/people"));
|
||||||
----
|
----
|
||||||
|
|
||||||
[[spring-mvc-test-server-filters]]
|
|
||||||
===== Filter Registrations
|
|
||||||
|
|
||||||
When setting up a `MockMvc` instance, you can register one or more Servlet `Filter`
|
[[spring-mvc-test-async-requests]]
|
||||||
instances, as the following example shows:
|
===== Async Requests
|
||||||
|
|
||||||
|
Servlet 3.0 asynchronous requests,
|
||||||
|
<<web.adoc#mvc-ann-async,supported in Spring MVC>>, work by exiting the Servlet container
|
||||||
|
thread and allowing the application to compute the response asynchronously, after which
|
||||||
|
an async dispatch is made to complete processing on a Servlet container thread.
|
||||||
|
|
||||||
|
In Spring MVC Test, async requests can be tested by asserting the produced async value
|
||||||
|
first, then manually performing the async dispatch, and finally verifying the response.
|
||||||
|
Below is an example test for controller methods that return `DeferredResult`, `Callable`,
|
||||||
|
or reactive type such as Reactor `Mono`:
|
||||||
|
|
||||||
[source,java,indent=0]
|
[source,java,indent=0]
|
||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
mockMvc = standaloneSetup(new PersonController()).addFilters(new CharacterEncodingFilter()).build();
|
@Test
|
||||||
----
|
public void test() throws Exception {
|
||||||
|
MvcResult mvcResult = this.mockMvc.perform(get("/path"))
|
||||||
|
.andExpect(status().isOk()) <1>
|
||||||
|
.andExpect(request().asyncStarted()) <2>
|
||||||
|
.andExpect(request().asyncResult("body")) <3>
|
||||||
|
.andReturn();
|
||||||
|
|
||||||
Registered filters are invoked through the `MockFilterChain` from `spring-test`, and the
|
this.mockMvc.perform(asyncDispatch(mvcResult)) <4>
|
||||||
last filter delegates to the `DispatcherServlet`.
|
.andExpect(status().isOk()) <5>
|
||||||
|
.andExpect(content().string("body"));
|
||||||
|
}
|
||||||
|
----
|
||||||
|
<1> Check response status is still unchanged
|
||||||
|
<2> Async processing must have started
|
||||||
|
<3> Wait and assert the async result
|
||||||
|
<4> Manually perform an ASYNC dispatch (as there is no running container)
|
||||||
|
<5> Verify the final response
|
||||||
|
|
||||||
|
====
|
||||||
|
|
||||||
|
|
||||||
[[spring-mvc-test-vs-streaming-response]]
|
[[spring-mvc-test-vs-streaming-response]]
|
||||||
|
@ -5108,13 +5131,31 @@ with `WebTestClient`. One extra advantage is the ability to use the `StepVerifie
|
||||||
project Reactor that allows declaring expectations on a stream of data.
|
project Reactor that allows declaring expectations on a stream of data.
|
||||||
|
|
||||||
|
|
||||||
[[spring-mvc-test-vs-end-to-end-integration-tests]]
|
[[spring-mvc-test-server-filters]]
|
||||||
===== Differences Between Out-of-Container and End-to-End Integration Tests
|
===== Filter Registrations
|
||||||
|
|
||||||
As mentioned earlier Spring MVC Test is built on the Servlet API mock objects from the
|
When setting up a `MockMvc` instance, you can register one or more Servlet `Filter`
|
||||||
`spring-test` module and does not use a running Servlet container. Therefore, there are
|
instances, as the following example shows:
|
||||||
some important differences compared to full end-to-end integration tests with an actual
|
|
||||||
client and server running.
|
====
|
||||||
|
[source,java,indent=0]
|
||||||
|
[subs="verbatim,quotes"]
|
||||||
|
----
|
||||||
|
mockMvc = standaloneSetup(new PersonController()).addFilters(new CharacterEncodingFilter()).build();
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
Registered filters are invoked through the `MockFilterChain` from `spring-test`, and the
|
||||||
|
last filter delegates to the `DispatcherServlet`.
|
||||||
|
|
||||||
|
|
||||||
|
[[spring-mvc-test-vs-end-to-end-integration-tests]]
|
||||||
|
===== Spring MVC Test vs End-to-End Tests
|
||||||
|
|
||||||
|
Spring MVC Test is built on Servlet API mock implementations from the
|
||||||
|
`spring-test` module and does not rely on a running container. Therefore, there are
|
||||||
|
some differences when compared to full end-to-end integration tests with an actual
|
||||||
|
client and a live server running.
|
||||||
|
|
||||||
The easiest way to think about this is by starting with a blank `MockHttpServletRequest`.
|
The easiest way to think about this is by starting with a blank `MockHttpServletRequest`.
|
||||||
Whatever you add to it is what the request becomes. Things that may catch you by surprise
|
Whatever you add to it is what the request becomes. Things that may catch you by surprise
|
||||||
|
@ -5155,7 +5196,7 @@ important thing to check. In short, there is room here for multiple styles and s
|
||||||
of testing even within the same project.
|
of testing even within the same project.
|
||||||
|
|
||||||
[[spring-mvc-test-server-resources]]
|
[[spring-mvc-test-server-resources]]
|
||||||
===== Further Server-Side Test Examples
|
===== Further Examples
|
||||||
|
|
||||||
The framework's own tests include
|
The framework's own tests include
|
||||||
https://github.com/spring-projects/spring-framework/tree/master/spring-test/src/test/java/org/springframework/test/web/servlet/samples[many
|
https://github.com/spring-projects/spring-framework/tree/master/spring-test/src/test/java/org/springframework/test/web/servlet/samples[many
|
||||||
|
|
Loading…
Reference in New Issue