diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MockMvcTester.java b/spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MockMvcTester.java
index c0d4546e083..5dd258ee987 100644
--- a/spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MockMvcTester.java
+++ b/spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MockMvcTester.java
@@ -23,13 +23,18 @@ import java.util.Map;
import java.util.function.Function;
import java.util.stream.StreamSupport;
+import org.assertj.core.api.AssertProvider;
+
+import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.converter.GenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
+import org.springframework.mock.web.MockHttpServletRequest;
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.request.AbstractMockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
@@ -58,11 +63,25 @@ import org.springframework.web.context.WebApplicationContext;
* MockMvcTester mvc = MockMvcTester.of(new PersonController());
*
*
- *
Once a tester instance is available, you can perform requests in a similar
- * fashion as with {@link MockMvc}, and wrapping the result in
- * {@code assertThat()} provides access to assertions. For instance:
+ *
Simple, single-statement assertions can be done wrapping the request
+ * builder in {@code assertThat()} provides access to assertions. For instance:
*
* // perform a GET on /hi and assert the response body is equal to Hello
+ * assertThat(mvc.get().uri("/hi")).hasStatusOk().hasBodyTextEqualTo("Hello");
+ *
+ *
+ *For more complex scenarios the {@linkplain MvcTestResult result} of the
+ * exchange can be assigned in a variable to run multiple assertions:
+ *
+ * // perform a POST on /save and assert the response body is empty
+ * MvcTestResult result = mvc.post().uri("/save").exchange();
+ * assertThat(result).hasStatus(HttpStatus.CREATED);
+ * assertThat(result).body().isEmpty();
+ *
+ *
+ * You can also perform requests using the static builders approach that
+ * {@link MockMvc} uses. For instance:
+ * // perform a GET on /hi and assert the response body is equal to Hello
* assertThat(mvc.perform(get("/hi")))
* .hasStatusOk().hasBodyTextEqualTo("Hello");
*
@@ -74,12 +93,11 @@ import org.springframework.web.context.WebApplicationContext;
* which allows you to assert that a request failed unexpectedly:
*
* // perform a GET on /boom and assert the message for the the unresolved exception
- * assertThat(mvc.perform(get("/boom")))
- * .hasUnresolvedException())
+ * assertThat(mvc.get().uri("/boom")).hasUnresolvedException())
* .withMessage("Test exception");
*
*
- * {@link MockMvcTester} can be configured with a list of
+ *
{@code MockMvcTester} can be configured with a list of
* {@linkplain HttpMessageConverter message converters} to allow the response
* body to be deserialized, rather than asserting on the raw values.
*
@@ -104,8 +122,7 @@ public final class MockMvcTester {
}
/**
- * Create a {@link MockMvcTester} instance that delegates to the given
- * {@link MockMvc} instance.
+ * Create an instance that delegates to the given {@link MockMvc} instance.
* @param mockMvc the MockMvc instance to delegate calls to
*/
public static MockMvcTester create(MockMvc mockMvc) {
@@ -113,9 +130,9 @@ public final class MockMvcTester {
}
/**
- * Create an {@link MockMvcTester} instance using the given, fully
- * initialized (i.e., refreshed) {@link WebApplicationContext}. The
- * given {@code customizations} are applied to the {@link DefaultMockMvcBuilder}
+ * Create an instance using the given, fully initialized (i.e.,
+ * refreshed) {@link WebApplicationContext}. The given
+ * {@code customizations} are applied to the {@link DefaultMockMvcBuilder}
* that ultimately creates the underlying {@link MockMvc} instance.
*
If no further customization of the underlying {@link MockMvc} instance
* is required, use {@link #from(WebApplicationContext)}.
@@ -134,8 +151,8 @@ public final class MockMvcTester {
}
/**
- * Shortcut to create an {@link MockMvcTester} instance using the given,
- * fully initialized (i.e., refreshed) {@link WebApplicationContext}.
+ * Shortcut to create an instance using the given fully initialized (i.e.,
+ * refreshed) {@link WebApplicationContext}.
*
Consider using {@link #from(WebApplicationContext, Function)} if
* further customization of the underlying {@link MockMvc} instance is
* required.
@@ -148,9 +165,8 @@ public final class MockMvcTester {
}
/**
- * Create an {@link MockMvcTester} instance by registering one or more
- * {@code @Controller} instances and configuring Spring MVC infrastructure
- * programmatically.
+ * Create an instance by registering one or more {@code @Controller} instances
+ * and configuring Spring MVC infrastructure programmatically.
*
This allows full control over the instantiation and initialization of
* controllers and their dependencies, similar to plain unit tests while
* also making it possible to test one controller at a time.
@@ -170,8 +186,8 @@ public final class MockMvcTester {
}
/**
- * Shortcut to create an {@link MockMvcTester} instance by registering one
- * or more {@code @Controller} instances.
+ * Shortcut to create an instance by registering one or more {@code @Controller}
+ * instances.
*
The minimum infrastructure required by the
* {@link org.springframework.web.servlet.DispatcherServlet DispatcherServlet}
* to serve requests with annotated controllers is created. Consider using
@@ -187,8 +203,8 @@ public final class MockMvcTester {
}
/**
- * Return a new {@link MockMvcTester} instance using the specified
- * {@linkplain HttpMessageConverter message converters}.
+ * Return a new instance using the specified {@linkplain HttpMessageConverter
+ * message converters}.
*
If none are specified, only basic assertions on the response body can
* be performed. Consider registering a suitable JSON converter for asserting
* against JSON data structures.
@@ -200,8 +216,105 @@ public final class MockMvcTester {
}
/**
- * Perform a request and return a {@link MvcTestResult result} that can be
- * used with standard {@link org.assertj.core.api.Assertions AssertJ} assertions.
+ * Prepare an HTTP GET request.
+ *
The returned builder can be wrapped in {@code assertThat} to enable
+ * assertions on the result. For multi-statements assertions, use
+ * {@linkplain MockMvcRequestBuilder#exchange() exchange} to assign the
+ * result.
+ * @return a request builder for specifying the target URI
+ */
+ public MockMvcRequestBuilder get() {
+ return method(HttpMethod.GET);
+ }
+
+ /**
+ * Prepare an HTTP HEAD request.
+ *
The returned builder can be wrapped in {@code assertThat} to enable
+ * assertions on the result. For multi-statements assertions, use
+ * {@linkplain MockMvcRequestBuilder#exchange() exchange} to assign the
+ * result.
+ * @return a request builder for specifying the target URI
+ */
+ public MockMvcRequestBuilder head() {
+ return method(HttpMethod.HEAD);
+ }
+
+ /**
+ * Prepare an HTTP POST request.
+ *
The returned builder can be wrapped in {@code assertThat} to enable
+ * assertions on the result. For multi-statements assertions, use
+ * {@linkplain MockMvcRequestBuilder#exchange() exchange} to assign the
+ * result.
+ * @return a request builder for specifying the target URI
+ */
+ public MockMvcRequestBuilder post() {
+ return method(HttpMethod.POST);
+ }
+
+ /**
+ * Prepare an HTTP PUT request.
+ *
The returned builder can be wrapped in {@code assertThat} to enable
+ * assertions on the result. For multi-statements assertions, use
+ * {@linkplain MockMvcRequestBuilder#exchange() exchange} to assign the
+ * result.
+ * @return a request builder for specifying the target URI
+ */
+ public MockMvcRequestBuilder put() {
+ return method(HttpMethod.PUT);
+ }
+
+ /**
+ * Prepare an HTTP PATCH request.
+ *
The returned builder can be wrapped in {@code assertThat} to enable
+ * assertions on the result. For multi-statements assertions, use
+ * {@linkplain MockMvcRequestBuilder#exchange() exchange} to assign the
+ * result.
+ * @return a request builder for specifying the target URI
+ */
+ public MockMvcRequestBuilder patch() {
+ return method(HttpMethod.PATCH);
+ }
+
+ /**
+ * Prepare an HTTP DELETE request.
+ *
The returned builder can be wrapped in {@code assertThat} to enable
+ * assertions on the result. For multi-statements assertions, use
+ * {@linkplain MockMvcRequestBuilder#exchange() exchange} to assign the
+ * result.
+ * @return a request builder for specifying the target URI
+ */
+ public MockMvcRequestBuilder delete() {
+ return method(HttpMethod.DELETE);
+ }
+
+ /**
+ * Prepare an HTTP OPTIONS request.
+ *
The returned builder can be wrapped in {@code assertThat} to enable
+ * assertions on the result. For multi-statements assertions, use
+ * {@linkplain MockMvcRequestBuilder#exchange() exchange} to assign the
+ * result.
+ * @return a request builder for specifying the target URI
+ */
+ public MockMvcRequestBuilder options() {
+ return method(HttpMethod.OPTIONS);
+ }
+
+ /**
+ * Prepare a request for the specified {@code HttpMethod}.
+ *
The returned builder can be wrapped in {@code assertThat} to enable
+ * assertions on the result. For multi-statements assertions, use
+ * {@linkplain MockMvcRequestBuilder#exchange() exchange} to assign the
+ * result.
+ * @return a request builder for specifying the target URI
+ */
+ public MockMvcRequestBuilder method(HttpMethod method) {
+ return new MockMvcRequestBuilder(method);
+ }
+
+ /**
+ * Perform a request using {@link MockMvcRequestBuilders} and return a
+ * {@link MvcTestResult result} that can be used with standard
+ * {@link org.assertj.core.api.Assertions AssertJ} assertions.
*
Use static methods of {@link MockMvcRequestBuilders} to prepare the
* request, wrapping the invocation in {@code assertThat}. The following
* asserts that a {@linkplain MockMvcRequestBuilders#get(URI) GET} request
@@ -226,6 +339,8 @@ public final class MockMvcTester {
* {@link org.springframework.test.web.servlet.request.MockMvcRequestBuilders}
* @return an {@link MvcTestResult} to be wrapped in {@code assertThat}
* @see MockMvc#perform(RequestBuilder)
+ * @see #get()
+ * @see #post()
*/
public MvcTestResult perform(RequestBuilder requestBuilder) {
Object result = getMvcResultOrFailure(requestBuilder);
@@ -259,4 +374,25 @@ public final class MockMvcTester {
.findFirst().orElse(null);
}
+
+ /**
+ * A builder for {@link MockHttpServletRequest} that supports AssertJ.
+ */
+ public final class MockMvcRequestBuilder extends AbstractMockHttpServletRequestBuilder
+ implements AssertProvider {
+
+ private MockMvcRequestBuilder(HttpMethod httpMethod) {
+ super(httpMethod);
+ }
+
+ public MvcTestResult exchange() {
+ return perform(this);
+ }
+
+ @Override
+ public MvcTestResultAssert assertThat() {
+ return new MvcTestResultAssert(exchange(), MockMvcTester.this.jsonMessageConverter);
+ }
+ }
+
}
diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/assertj/MockMvcTesterCompatibilityIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/assertj/MockMvcTesterCompatibilityIntegrationTests.java
new file mode 100644
index 00000000000..712b725d90f
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/web/servlet/assertj/MockMvcTesterCompatibilityIntegrationTests.java
@@ -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\"}";
+ }
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/assertj/MockMvcTesterIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/assertj/MockMvcTesterIntegrationTests.java
index 90f68c1f553..6778de3fbd0 100644
--- a/spring-test/src/test/java/org/springframework/test/web/servlet/assertj/MockMvcTesterIntegrationTests.java
+++ b/spring-test/src/test/java/org/springframework/test/web/servlet/assertj/MockMvcTesterIntegrationTests.java
@@ -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 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 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,