Add support for fluent preparation of the request in MockMvcTester
See gh-32913
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.web.servlet.assertj;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link MockMvcTester} that use the methods that
|
||||
* integrate with {@link MockMvc} way of building the requests and
|
||||
* asserting the responses.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@SpringJUnitConfig
|
||||
@WebAppConfiguration
|
||||
class MockMvcTesterCompatibilityIntegrationTests {
|
||||
|
||||
private final MockMvcTester mvc;
|
||||
|
||||
MockMvcTesterCompatibilityIntegrationTests(@Autowired WebApplicationContext wac) {
|
||||
this.mvc = MockMvcTester.from(wac);
|
||||
}
|
||||
|
||||
@Test
|
||||
void performGet() {
|
||||
assertThat(this.mvc.perform(get("/greet"))).hasStatusOk();
|
||||
}
|
||||
|
||||
@Test
|
||||
void performGetWithInvalidMediaTypeAssertion() {
|
||||
MvcTestResult result = this.mvc.perform(get("/greet"));
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(result).hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON))
|
||||
.withMessageContaining("is compatible with 'application/json'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void assertHttpStatusCode() {
|
||||
assertThat(this.mvc.get().uri("/greet")).matches(status().isOk());
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@Import(TestController.class)
|
||||
static class WebConfiguration {
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class TestController {
|
||||
|
||||
@GetMapping(path = "/greet", produces = "text/plain")
|
||||
String greet() {
|
||||
return "hello";
|
||||
}
|
||||
|
||||
@GetMapping(path = "/message", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
String message() {
|
||||
return "{\"message\": \"hello\"}";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,7 +43,7 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.Person;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -63,9 +63,8 @@ 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.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link MockMvcTester}.
|
||||
@@ -77,10 +76,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
@WebAppConfiguration
|
||||
public class MockMvcTesterIntegrationTests {
|
||||
|
||||
private final MockMvcTester mockMvc;
|
||||
private final MockMvcTester mvc;
|
||||
|
||||
MockMvcTesterIntegrationTests(WebApplicationContext wac) {
|
||||
this.mockMvc = MockMvcTester.from(wac);
|
||||
this.mvc = MockMvcTester.from(wac);
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -88,24 +87,24 @@ public class MockMvcTesterIntegrationTests {
|
||||
|
||||
@Test
|
||||
void hasAsyncStartedTrue() {
|
||||
assertThat(perform(get("/callable").accept(MediaType.APPLICATION_JSON)))
|
||||
assertThat(mvc.get().uri("/callable").accept(MediaType.APPLICATION_JSON))
|
||||
.request().hasAsyncStarted(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAsyncStartedFalse() {
|
||||
assertThat(perform(get("/greet"))).request().hasAsyncStarted(false);
|
||||
assertThat(mvc.get().uri("/greet")).request().hasAsyncStarted(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void attributes() {
|
||||
assertThat(perform(get("/greet"))).request().attributes()
|
||||
assertThat(mvc.get().uri("/greet")).request().attributes()
|
||||
.containsKey(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionAttributes() {
|
||||
assertThat(perform(get("/locale"))).request().sessionAttributes()
|
||||
assertThat(mvc.get().uri("/locale")).request().sessionAttributes()
|
||||
.containsOnly(entry("locale", Locale.UK));
|
||||
}
|
||||
}
|
||||
@@ -116,17 +115,17 @@ public class MockMvcTesterIntegrationTests {
|
||||
@Test
|
||||
void containsCookie() {
|
||||
Cookie cookie = new Cookie("test", "value");
|
||||
assertThat(performWithCookie(cookie, get("/greet"))).cookies().containsCookie("test");
|
||||
assertThat(withCookie(cookie).get().uri("/greet")).cookies().containsCookie("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasValue() {
|
||||
Cookie cookie = new Cookie("test", "value");
|
||||
assertThat(performWithCookie(cookie, get("/greet"))).cookies().hasValue("test", "value");
|
||||
assertThat(withCookie(cookie).get().uri("/greet")).cookies().hasValue("test", "value");
|
||||
}
|
||||
|
||||
private MvcTestResult performWithCookie(Cookie cookie, MockHttpServletRequestBuilder request) {
|
||||
MockMvcTester mockMvc = MockMvcTester.of(List.of(new TestController()), builder -> builder.addInterceptors(
|
||||
private MockMvcTester withCookie(Cookie cookie) {
|
||||
return MockMvcTester.of(List.of(new TestController()), builder -> builder.addInterceptors(
|
||||
new HandlerInterceptor() {
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
@@ -134,7 +133,6 @@ public class MockMvcTesterIntegrationTests {
|
||||
return true;
|
||||
}
|
||||
}).build());
|
||||
return mockMvc.perform(request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,12 +141,12 @@ public class MockMvcTesterIntegrationTests {
|
||||
|
||||
@Test
|
||||
void statusOk() {
|
||||
assertThat(perform(get("/greet"))).hasStatusOk();
|
||||
assertThat(mvc.get().uri("/greet")).hasStatusOk();
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusSeries() {
|
||||
assertThat(perform(get("/greet"))).hasStatus2xxSuccessful();
|
||||
assertThat(mvc.get().uri("/greet")).hasStatus2xxSuccessful();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -158,13 +156,13 @@ public class MockMvcTesterIntegrationTests {
|
||||
|
||||
@Test
|
||||
void shouldAssertHeader() {
|
||||
assertThat(perform(get("/greet")))
|
||||
assertThat(mvc.get().uri("/greet"))
|
||||
.hasHeader("Content-Type", "text/plain;charset=ISO-8859-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAssertHeaderWithCallback() {
|
||||
assertThat(perform(get("/greet"))).headers().satisfies(textContent("ISO-8859-1"));
|
||||
assertThat(mvc.get().uri("/greet")).headers().satisfies(textContent("ISO-8859-1"));
|
||||
}
|
||||
|
||||
private Consumer<HttpHeaders> textContent(String charset) {
|
||||
@@ -179,33 +177,33 @@ public class MockMvcTesterIntegrationTests {
|
||||
|
||||
@Test
|
||||
void hasViewName() {
|
||||
assertThat(perform(get("/persons/{0}", "Andy"))).hasViewName("persons/index");
|
||||
assertThat(mvc.get().uri("/persons/{0}", "Andy")).hasViewName("persons/index");
|
||||
}
|
||||
|
||||
@Test
|
||||
void viewNameWithCustomAssertion() {
|
||||
assertThat(perform(get("/persons/{0}", "Andy"))).viewName().startsWith("persons");
|
||||
assertThat(mvc.get().uri("/persons/{0}", "Andy")).viewName().startsWith("persons");
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsAttributes() {
|
||||
assertThat(perform(post("/persons").param("name", "Andy"))).model()
|
||||
assertThat(mvc.post().uri("/persons").param("name", "Andy")).model()
|
||||
.containsOnlyKeys("name").containsEntry("name", "Andy");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasErrors() {
|
||||
assertThat(perform(post("/persons"))).model().hasErrors();
|
||||
assertThat(mvc.post().uri("/persons")).model().hasErrors();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAttributeErrors() {
|
||||
assertThat(perform(post("/persons"))).model().hasAttributeErrors("person");
|
||||
assertThat(mvc.post().uri("/persons")).model().hasAttributeErrors("person");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasAttributeErrorsCount() {
|
||||
assertThat(perform(post("/persons"))).model().extractingBindingResult("person").hasErrorsCount(1);
|
||||
assertThat(mvc.post().uri("/persons")).model().extractingBindingResult("person").hasErrorsCount(1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -215,7 +213,7 @@ public class MockMvcTesterIntegrationTests {
|
||||
|
||||
@Test
|
||||
void containsAttributes() {
|
||||
assertThat(perform(post("/persons").param("name", "Andy"))).flash()
|
||||
assertThat(mvc.post().uri("/persons").param("name", "Andy")).flash()
|
||||
.containsOnlyKeys("message").hasEntrySatisfying("message",
|
||||
value -> assertThat(value).isInstanceOfSatisfying(String.class,
|
||||
stringValue -> assertThat(stringValue).startsWith("success")));
|
||||
@@ -227,31 +225,31 @@ public class MockMvcTesterIntegrationTests {
|
||||
|
||||
@Test
|
||||
void asyncResult() {
|
||||
assertThat(perform(get("/callable").accept(MediaType.APPLICATION_JSON)))
|
||||
assertThat(mvc.get().uri("/callable").accept(MediaType.APPLICATION_JSON))
|
||||
.asyncResult().asInstanceOf(map(String.class, Object.class))
|
||||
.containsOnly(entry("key", "value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void stringContent() {
|
||||
assertThat(perform(get("/greet"))).body().asString().isEqualTo("hello");
|
||||
assertThat(mvc.get().uri("/greet")).body().asString().isEqualTo("hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
void jsonPathContent() {
|
||||
assertThat(perform(get("/message"))).bodyJson()
|
||||
assertThat(mvc.get().uri("/message")).bodyJson()
|
||||
.extractingPath("$.message").asString().isEqualTo("hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
void jsonContentCanLoadResourceFromClasspath() {
|
||||
assertThat(perform(get("/message"))).bodyJson().isLenientlyEqualTo(
|
||||
assertThat(mvc.get().uri("/message")).bodyJson().isLenientlyEqualTo(
|
||||
new ClassPathResource("message.json", MockMvcTesterIntegrationTests.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void jsonContentUsingResourceLoaderClass() {
|
||||
assertThat(perform(get("/message"))).bodyJson().withResourceLoadClass(MockMvcTesterIntegrationTests.class)
|
||||
assertThat(mvc.get().uri("/message")).bodyJson().withResourceLoadClass(MockMvcTesterIntegrationTests.class)
|
||||
.isLenientlyEqualTo("message.json");
|
||||
}
|
||||
|
||||
@@ -262,22 +260,22 @@ public class MockMvcTesterIntegrationTests {
|
||||
|
||||
@Test
|
||||
void handlerOn404() {
|
||||
assertThat(perform(get("/unknown-resource"))).handler().isNull();
|
||||
assertThat(mvc.get().uri("/unknown-resource")).handler().isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasType() {
|
||||
assertThat(perform(get("/greet"))).handler().hasType(TestController.class);
|
||||
assertThat(mvc.get().uri("/greet")).handler().hasType(TestController.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void isMethodHandler() {
|
||||
assertThat(perform(get("/greet"))).handler().isMethodHandler();
|
||||
assertThat(mvc.get().uri("/greet")).handler().isMethodHandler();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isInvokedOn() {
|
||||
assertThat(perform(get("/callable"))).handler()
|
||||
assertThat(mvc.get().uri("/callable")).handler()
|
||||
.isInvokedOn(AsyncController.class, AsyncController::getCallable);
|
||||
}
|
||||
|
||||
@@ -288,31 +286,31 @@ public class MockMvcTesterIntegrationTests {
|
||||
|
||||
@Test
|
||||
void doesNotHaveUnresolvedException() {
|
||||
assertThat(perform(get("/greet"))).doesNotHaveUnresolvedException();
|
||||
assertThat(mvc.get().uri("/greet")).doesNotHaveUnresolvedException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasUnresolvedException() {
|
||||
assertThat(perform(get("/error/1"))).hasUnresolvedException();
|
||||
assertThat(mvc.get().uri("/error/1")).hasUnresolvedException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotHaveUnresolvedExceptionWithUnresolvedException() {
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(perform(get("/error/1"))).doesNotHaveUnresolvedException())
|
||||
.isThrownBy(() -> assertThat(mvc.get().uri("/error/1")).doesNotHaveUnresolvedException())
|
||||
.withMessage("Expected request to succeed, but it failed");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasUnresolvedExceptionWithoutUnresolvedException() {
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(perform(get("/greet"))).hasUnresolvedException())
|
||||
.isThrownBy(() -> assertThat(mvc.get().uri("/greet")).hasUnresolvedException())
|
||||
.withMessage("Expected request to fail, but it succeeded");
|
||||
}
|
||||
|
||||
@Test
|
||||
void unresolvedExceptionWithFailedRequest() {
|
||||
assertThat(perform(get("/error/1"))).unresolvedException()
|
||||
assertThat(mvc.get().uri("/error/1")).unresolvedException()
|
||||
.isInstanceOf(ServletException.class)
|
||||
.cause().isInstanceOf(IllegalStateException.class).hasMessage("Expected");
|
||||
}
|
||||
@@ -320,7 +318,7 @@ public class MockMvcTesterIntegrationTests {
|
||||
@Test
|
||||
void unresolvedExceptionWithSuccessfulRequest() {
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(perform(get("/greet"))).unresolvedException())
|
||||
.isThrownBy(() -> assertThat(mvc.get().uri("/greet")).unresolvedException())
|
||||
.withMessage("Expected request to fail, but it succeeded");
|
||||
}
|
||||
|
||||
@@ -406,7 +404,7 @@ public class MockMvcTesterIntegrationTests {
|
||||
|
||||
|
||||
private void testAssertionFailureWithUnresolvableException(Consumer<MvcTestResult> assertions) {
|
||||
MvcTestResult result = perform(get("/error/1"));
|
||||
MvcTestResult result = mvc.get().uri("/error/1").exchange();
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertions.accept(result))
|
||||
.withMessageContainingAll("Request failed unexpectedly:",
|
||||
@@ -418,49 +416,49 @@ public class MockMvcTesterIntegrationTests {
|
||||
|
||||
@Test
|
||||
void hasForwardUrl() {
|
||||
assertThat(perform(get("/persons/John"))).hasForwardedUrl("persons/index");
|
||||
assertThat(mvc.get().uri("/persons/John")).hasForwardedUrl("persons/index");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasRedirectUrl() {
|
||||
assertThat(perform(post("/persons").param("name", "Andy"))).hasStatus(HttpStatus.FOUND)
|
||||
assertThat(mvc.post().uri("/persons").param("name", "Andy")).hasStatus(HttpStatus.FOUND)
|
||||
.hasRedirectedUrl("/persons/Andy");
|
||||
}
|
||||
|
||||
@Test
|
||||
void satisfiesAllowsAdditionalAssertions() {
|
||||
assertThat(this.mockMvc.perform(get("/greet"))).satisfies(result -> {
|
||||
assertThat(mvc.get().uri("/greet")).satisfies(result -> {
|
||||
assertThat(result).isInstanceOf(MvcTestResult.class);
|
||||
assertThat(result).hasStatusOk();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void resultMatcherCanBeReused() {
|
||||
assertThat(this.mockMvc.perform(get("/greet"))).matches(status().isOk());
|
||||
void resultMatcherCanBeReused() throws Exception {
|
||||
MvcTestResult result = mvc.get().uri("/greet").exchange();
|
||||
ResultMatcher matcher = mock(ResultMatcher.class);
|
||||
assertThat(result).matches(matcher);
|
||||
verify(matcher).match(result.getMvcResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resultMatcherFailsWithDedicatedException() {
|
||||
ResultMatcher matcher = result -> assertThat(result.getResponse().getStatus())
|
||||
.isEqualTo(HttpStatus.NOT_FOUND.value());
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(this.mockMvc.perform(get("/greet")))
|
||||
.matches(status().isNotFound()))
|
||||
.withMessageContaining("Status expected:<404> but was:<200>");
|
||||
.isThrownBy(() -> assertThat(mvc.get().uri("/greet"))
|
||||
.matches(matcher))
|
||||
.withMessageContaining("expected: 404").withMessageContaining(" but was: 200");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldApplyResultHandler() { // Spring RESTDocs example
|
||||
AtomicBoolean applied = new AtomicBoolean();
|
||||
assertThat(this.mockMvc.perform(get("/greet"))).apply(result -> applied.set(true));
|
||||
assertThat(mvc.get().uri("/greet")).apply(result -> applied.set(true));
|
||||
assertThat(applied).isTrue();
|
||||
}
|
||||
|
||||
|
||||
private MvcTestResult perform(MockHttpServletRequestBuilder builder) {
|
||||
return this.mockMvc.perform(builder);
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@Import({ TestController.class, PersonController.class, AsyncController.class,
|
||||
|
||||
Reference in New Issue
Block a user