Add explicit support for asynchronous requests in MockMvcTester
This commit makes asynchronous requests first class by providing a MvcTestResult that represents the final, completed, state of a request by default. Previously, the result was an intermediate step that may require an ASYNC dispatch to be fully usable. Now it is de facto immutable. To make things a bit more explicit, an `.exchange(Duration)` method has been added to provide a dedicated time to wait. The default applies a default timeout that is consistent with what MVcResult#getAsyncResult does. Given that we apply the ASYNC dispatch automatically, the intermediate response is no longer available by default. As a result, the asyncResult is not available for assertions. As always, it is possible to use plain MockMvc by using the `perform` method that takes the regular RequestBuilder as an input. When this method is invoked, no asynchronous handling is done. Closes gh-33040
This commit is contained in:
@@ -20,6 +20,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -36,6 +37,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.Part;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
@@ -53,6 +55,7 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
import org.springframework.test.web.servlet.assertj.MockMvcTester.MockMvcRequestBuilder;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -73,14 +76,16 @@ import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.map;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link MockMvcTester}.
|
||||
@@ -97,12 +102,60 @@ public class MockMvcTesterIntegrationTests {
|
||||
this.mvc = MockMvcTester.from(wac);
|
||||
}
|
||||
|
||||
@Nested
|
||||
class PerformTests {
|
||||
|
||||
@Test
|
||||
void syncRequestWithDefaultExchange() {
|
||||
assertThat(mvc.get().uri("/greet")).hasStatusOk();
|
||||
}
|
||||
|
||||
@Test
|
||||
void asyncRequestWithDefaultExchange() {
|
||||
assertThat(mvc.get().uri("/streaming").param("timeToWait", "100")).hasStatusOk()
|
||||
.hasBodyTextEqualTo("name=Joe&someBoolean=true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void syncRequestWithExplicitExchange() {
|
||||
assertThat(mvc.get().uri("/greet").exchange()).hasStatusOk();
|
||||
}
|
||||
|
||||
@Test
|
||||
void asyncRequestWithExplicitExchange() {
|
||||
assertThat(mvc.get().uri("/streaming").param("timeToWait", "100").exchange())
|
||||
.hasStatusOk().hasBodyTextEqualTo("name=Joe&someBoolean=true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void syncRequestWithExplicitExchangeIgnoresDuration() {
|
||||
Duration timeToWait = mock(Duration.class);
|
||||
assertThat(mvc.get().uri("/greet").exchange(timeToWait)).hasStatusOk();
|
||||
verifyNoInteractions(timeToWait);
|
||||
}
|
||||
|
||||
@Test
|
||||
void asyncRequestWithExplicitExchangeAndEnoughTimeToWait() {
|
||||
assertThat(mvc.get().uri("/streaming").param("timeToWait", "100").exchange(Duration.ofMillis(200)))
|
||||
.hasStatusOk().hasBodyTextEqualTo("name=Joe&someBoolean=true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void asyncRequestWithExplicitExchangeAndNotEnoughTimeToWait() {
|
||||
MockMvcRequestBuilder builder = mvc.get().uri("/streaming").param("timeToWait", "500");
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> builder.exchange(Duration.ofMillis(100)))
|
||||
.withMessageContaining("was not set during the specified timeToWait=100");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class RequestTests {
|
||||
|
||||
@Test
|
||||
void hasAsyncStartedTrue() {
|
||||
assertThat(mvc.get().uri("/callable").accept(MediaType.APPLICATION_JSON))
|
||||
// Need #perform as the regular exchange waits for async completion automatically
|
||||
assertThat(mvc.perform(mvc.get().uri("/callable").accept(MediaType.APPLICATION_JSON)))
|
||||
.request().hasAsyncStarted(true);
|
||||
}
|
||||
|
||||
@@ -272,8 +325,10 @@ public class MockMvcTesterIntegrationTests {
|
||||
|
||||
@Test
|
||||
void asyncResult() {
|
||||
assertThat(mvc.get().uri("/callable").accept(MediaType.APPLICATION_JSON))
|
||||
.asyncResult().asInstanceOf(map(String.class, Object.class))
|
||||
// Need #perform as the regular exchange waits for async completion automatically
|
||||
MvcTestResult result = mvc.perform(mvc.get().uri("/callable").accept(MediaType.APPLICATION_JSON));
|
||||
assertThat(result.getMvcResult().getAsyncResult())
|
||||
.asInstanceOf(InstanceOfAssertFactories.map(String.class, Object.class))
|
||||
.containsOnly(entry("key", "value"));
|
||||
}
|
||||
|
||||
@@ -441,12 +496,6 @@ public class MockMvcTesterIntegrationTests {
|
||||
result -> assertThat(result).apply(mvcResult -> {}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void assertAsyncResultWithUnresolvedException() {
|
||||
testAssertionFailureWithUnresolvableException(
|
||||
result -> assertThat(result).asyncResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
void assertContentTypeWithUnresolvedException() {
|
||||
testAssertionFailureWithUnresolvableException(
|
||||
@@ -617,6 +666,21 @@ public class MockMvcTesterIntegrationTests {
|
||||
public Callable<Map<String, String>> getCallable() {
|
||||
return () -> Collections.singletonMap("key", "value");
|
||||
}
|
||||
|
||||
@GetMapping("/streaming")
|
||||
StreamingResponseBody streaming(@RequestParam long timeToWait) {
|
||||
return out -> {
|
||||
PrintStream stream = new PrintStream(out, true, StandardCharsets.UTF_8);
|
||||
stream.print("name=Joe");
|
||||
try {
|
||||
Thread.sleep(timeToWait);
|
||||
stream.print("&someBoolean=true");
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
/* no-op */
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Controller
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,7 @@ import java.time.Duration;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -31,6 +32,9 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.RequestBuilder;
|
||||
import org.springframework.test.web.servlet.assertj.MockMvcTester;
|
||||
import org.springframework.test.web.servlet.assertj.MvcTestResult;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
@@ -58,132 +62,222 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal
|
||||
*/
|
||||
class AsyncTests {
|
||||
|
||||
private final AsyncController asyncController = new AsyncController();
|
||||
@Nested
|
||||
class MockMvcTests {
|
||||
|
||||
private final MockMvc mockMvc = standaloneSetup(this.asyncController).build();
|
||||
private final MockMvc mockMvc = standaloneSetup(new AsyncController()).build();
|
||||
|
||||
@Test
|
||||
void callable() throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("callable", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andExpect(request().asyncResult(equalTo(new Person("Joe"))))
|
||||
.andExpect(request().asyncResult(new Person("Joe")))
|
||||
.andReturn();
|
||||
|
||||
@Test
|
||||
void callable() throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("callable", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andExpect(request().asyncResult(equalTo(new Person("Joe"))))
|
||||
.andExpect(request().asyncResult(new Person("Joe")))
|
||||
.andReturn();
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
|
||||
}
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
|
||||
@Test
|
||||
void streaming() throws Exception {
|
||||
this.mockMvc.perform(get("/1").param("streaming", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andDo(MvcResult::getAsyncResult) // fetch async result similar to "asyncDispatch" builder
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string("name=Joe"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void streamingSlow() throws Exception {
|
||||
this.mockMvc.perform(get("/1").param("streamingSlow", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andDo(MvcResult::getAsyncResult)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string("name=Joe&someBoolean=true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void streamingJson() throws Exception {
|
||||
this.mockMvc.perform(get("/1").param("streamingJson", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andDo(MvcResult::getAsyncResult)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.5}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deferredResult() throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("deferredResult", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deferredResultWithImmediateValue() throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("deferredResultWithImmediateValue", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andExpect(request().asyncResult(new Person("Joe")))
|
||||
.andReturn();
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
|
||||
}
|
||||
|
||||
@Test // SPR-13079
|
||||
void deferredResultWithDelayedError() throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("deferredResultWithDelayedError", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().is5xxServerError())
|
||||
.andExpect(content().string("Delayed Error"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void listenableFuture() throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("listenableFuture", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
|
||||
}
|
||||
|
||||
@Test // SPR-12597
|
||||
void completableFutureWithImmediateValue() throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("completableFutureWithImmediateValue", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
|
||||
}
|
||||
|
||||
@Test // SPR-12735
|
||||
void printAsyncResult() throws Exception {
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("deferredResult", "true"))
|
||||
.andDo(print(writer))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
|
||||
assertThat(writer.toString()).contains("Async started = true");
|
||||
writer = new StringWriter();
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andDo(print(writer))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
|
||||
|
||||
assertThat(writer.toString()).contains("Async started = false");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void streaming() throws Exception {
|
||||
this.mockMvc.perform(get("/1").param("streaming", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andDo(MvcResult::getAsyncResult) // fetch async result similar to "asyncDispatch" builder
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string("name=Joe"));
|
||||
}
|
||||
@Nested
|
||||
class MockMvcTesterTests {
|
||||
|
||||
@Test
|
||||
void streamingSlow() throws Exception {
|
||||
this.mockMvc.perform(get("/1").param("streamingSlow", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andDo(MvcResult::getAsyncResult)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string("name=Joe&someBoolean=true"));
|
||||
}
|
||||
private final MockMvcTester mockMvc = MockMvcTester.of(new AsyncController());
|
||||
|
||||
@Test
|
||||
void streamingJson() throws Exception {
|
||||
this.mockMvc.perform(get("/1").param("streamingJson", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andDo(MvcResult::getAsyncResult)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.5}"));
|
||||
}
|
||||
@Test
|
||||
void callable() {
|
||||
assertThat(mockMvc.get().uri("/1").param("callable", "true"))
|
||||
.hasStatusOk()
|
||||
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON)
|
||||
.hasBodyTextEqualTo("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
@Test
|
||||
void deferredResult() throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("deferredResult", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
@Test
|
||||
void streaming() {
|
||||
assertThat(this.mockMvc.get().uri("/1").param("streaming", "true"))
|
||||
.hasStatusOk().hasBodyTextEqualTo("name=Joe");
|
||||
}
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
|
||||
}
|
||||
@Test
|
||||
void streamingSlow() {
|
||||
assertThat(this.mockMvc.get().uri("/1").param("streamingSlow", "true"))
|
||||
.hasStatusOk().hasBodyTextEqualTo("name=Joe&someBoolean=true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void deferredResultWithImmediateValue() throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("deferredResultWithImmediateValue", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andExpect(request().asyncResult(new Person("Joe")))
|
||||
.andReturn();
|
||||
@Test
|
||||
void streamingJson() {
|
||||
assertThat(this.mockMvc.get().uri("/1").param("streamingJson", "true"))
|
||||
.hasStatusOk()
|
||||
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON)
|
||||
.hasBodyTextEqualTo("{\"name\":\"Joe\",\"someDouble\":0.5}");
|
||||
}
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
|
||||
}
|
||||
@Test
|
||||
void deferredResult() {
|
||||
assertThat(this.mockMvc.get().uri("/1").param("deferredResult", "true"))
|
||||
.hasStatusOk()
|
||||
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON)
|
||||
.hasBodyTextEqualTo("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
@Test // SPR-13079
|
||||
void deferredResultWithDelayedError() throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("deferredResultWithDelayedError", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
@Test
|
||||
void deferredResultWithImmediateValue() {
|
||||
assertThat(this.mockMvc.get().uri("/1").param("deferredResultWithImmediateValue", "true"))
|
||||
.hasStatusOk()
|
||||
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON)
|
||||
.hasBodyTextEqualTo("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().is5xxServerError())
|
||||
.andExpect(content().string("Delayed Error"));
|
||||
}
|
||||
@Test // SPR-13079
|
||||
void deferredResultWithDelayedError() {
|
||||
assertThat(this.mockMvc.get().uri("/1").param("deferredResultWithDelayedError", "true"))
|
||||
.hasStatus5xxServerError().hasBodyTextEqualTo("Delayed Error");
|
||||
}
|
||||
|
||||
@Test
|
||||
void listenableFuture() throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("listenableFuture", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
@Test
|
||||
void listenableFuture() {
|
||||
assertThat(this.mockMvc.get().uri("/1").param("listenableFuture", "true"))
|
||||
.hasStatusOk().hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON)
|
||||
.hasBodyTextEqualTo("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
|
||||
}
|
||||
@Test // SPR-12597
|
||||
void completableFutureWithImmediateValue() {
|
||||
assertThat(this.mockMvc.get().uri("/1").param("completableFutureWithImmediateValue", "true"))
|
||||
.hasStatusOk()
|
||||
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON)
|
||||
.hasBodyTextEqualTo("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
}
|
||||
|
||||
@Test // SPR-12597
|
||||
void completableFutureWithImmediateValue() throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("completableFutureWithImmediateValue", "true"))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
@Test // SPR-12735
|
||||
void printAsyncResult() {
|
||||
StringWriter asyncWriter = new StringWriter();
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
|
||||
}
|
||||
|
||||
@Test // SPR-12735
|
||||
void printAsyncResult() throws Exception {
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("deferredResult", "true"))
|
||||
.andDo(print(writer))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
|
||||
assertThat(writer.toString()).contains("Async started = true");
|
||||
writer = new StringWriter();
|
||||
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult))
|
||||
.andDo(print(writer))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
|
||||
|
||||
assertThat(writer.toString()).contains("Async started = false");
|
||||
// Use #perform to not complete asynchronous request automatically
|
||||
RequestBuilder requestBuilder = this.mockMvc.get().uri("/1").param("deferredResult", "true");
|
||||
MvcTestResult result = this.mockMvc.perform(requestBuilder);
|
||||
assertThat(result).debug(asyncWriter).request().hasAsyncStarted(true);
|
||||
assertThat(asyncWriter.toString()).contains("Async started = true");
|
||||
asyncWriter = new StringWriter(); // Reset
|
||||
assertThat(this.mockMvc.perform(asyncDispatch(result.getMvcResult())))
|
||||
.debug(asyncWriter)
|
||||
.hasStatusOk()
|
||||
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON)
|
||||
.hasBodyTextEqualTo("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
|
||||
assertThat(asyncWriter.toString()).contains("Async started = false");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user