Browse Source

Streamline assertions on exceptions

This commit simplifies assertions on MockMvc requests that have failed
to process. A now general hasFailed/doesNotHaveFailed/failure provides
the necessary to assert the exception.

Any attempt to access anything from the result with an unresolved
exception still fails as before.

Closes gh-33060
pull/33073/head
Stéphane Nicoll 2 years ago
parent
commit
84bcb65dd1
  1. 18
      spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MockMvcTester.java
  2. 33
      spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MvcTestResultAssert.java
  3. 49
      spring-test/src/test/java/org/springframework/test/web/servlet/assertj/MockMvcTesterIntegrationTests.java

18
spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MockMvcTester.java

@ -89,12 +89,20 @@ import org.springframework.web.context.WebApplicationContext;
* <p>One main difference between {@link MockMvc} and {@code MockMvcTester} is * <p>One main difference between {@link MockMvc} and {@code MockMvcTester} is
* that an unresolved exception is not thrown directly when using * that an unresolved exception is not thrown directly when using
* {@code MockMvcTester}. Rather an {@link MvcTestResult} is available with an * {@code MockMvcTester}. Rather an {@link MvcTestResult} is available with an
* {@linkplain MvcTestResult#getUnresolvedException() unresolved exception} * {@linkplain MvcTestResult#getUnresolvedException() unresolved exception}.
* which allows you to assert that a request failed unexpectedly: * Both resolved and unresolved exceptions are considered a failure that can
* be asserted as follows:
* <pre><code class="java"> * <pre><code class="java">
* // perform a GET on /boom and assert the message for the the unresolved exception * // perform a GET on /boom and assert the message for the the exception
* assertThat(mvc.get().uri("/boom")).hasUnresolvedException()) * assertThat(mvc.get().uri("/boom")).hasFailed()
* .withMessage("Test exception"); * .failure().hasMessage("Test exception");
* </code></pre>
*
* <p>Any attempt to access the result with an unresolved exception will
* throw an {@link AssertionError}:
* <pre><code class="java">
* // throw an AssertionError with an unresolved exception
* assertThat(mvc.get().uri("/boom")).hasStatus5xxServerError();
* </code></pre> * </code></pre>
* *
* <p>{@code MockMvcTester} can be configured with a list of * <p>{@code MockMvcTester} can be configured with a list of

33
spring-test/src/main/java/org/springframework/test/web/servlet/assertj/MvcTestResultAssert.java

@ -59,13 +59,13 @@ public class MvcTestResultAssert extends AbstractMockHttpServletResponseAssert<M
} }
/** /**
* Verify that the request failed with an unresolved exception, and * Verify that the request has failed and return a new
* return a new {@linkplain AbstractThrowableAssert assertion} object * {@linkplain AbstractThrowableAssert assertion} object that uses the
* that uses the unresolved {@link Exception} as the object to test. * failure as the object to test.
*/ */
public AbstractThrowableAssert<?, ? extends Throwable> unresolvedException() { public AbstractThrowableAssert<?, ? extends Throwable> failure() {
hasUnresolvedException(); hasFailed();
return Assertions.assertThat(this.actual.getUnresolvedException()); return Assertions.assertThat(getFailure());
} }
/** /**
@ -137,20 +137,19 @@ public class MvcTestResultAssert extends AbstractMockHttpServletResponseAssert<M
} }
/** /**
* Verify that the request failed with an unresolved exception. * Verify that the request has failed.
* @see #unresolvedException()
*/ */
public MvcTestResultAssert hasUnresolvedException() { public MvcTestResultAssert hasFailed() {
Assertions.assertThat(this.actual.getUnresolvedException()) Assertions.assertThat(getFailure())
.withFailMessage("Expected request to fail, but it succeeded").isNotNull(); .withFailMessage("Expected request to fail, but it succeeded").isNotNull();
return this; return this;
} }
/** /**
* Verify that the request did not fail with an unresolved exception. * Verify that the request has not failed.
*/ */
public MvcTestResultAssert doesNotHaveUnresolvedException() { public MvcTestResultAssert doesNotHaveFailed() {
Assertions.assertThat(this.actual.getUnresolvedException()) Assertions.assertThat(getFailure())
.withFailMessage("Expected request to succeed, but it failed").isNull(); .withFailMessage("Expected request to succeed, but it failed").isNull();
return this; return this;
} }
@ -184,6 +183,14 @@ public class MvcTestResultAssert extends AbstractMockHttpServletResponseAssert<M
return this.myself; return this.myself;
} }
@Nullable
private Throwable getFailure() {
Exception unresolvedException = this.actual.getUnresolvedException();
if (unresolvedException != null) {
return unresolvedException;
}
return this.actual.getMvcResult().getResolvedException();
}
@SuppressWarnings("NullAway") @SuppressWarnings("NullAway")
private ModelAndView getModelAndView() { private ModelAndView getModelAndView() {

49
spring-test/src/test/java/org/springframework/test/web/servlet/assertj/MockMvcTesterIntegrationTests.java

@ -53,6 +53,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@ -278,40 +279,59 @@ public class MockMvcTesterIntegrationTests {
class ExceptionTests { class ExceptionTests {
@Test @Test
void doesNotHaveUnresolvedException() { void hasFailedWithUnresolvedException() {
assertThat(mvc.get().uri("/greet")).doesNotHaveUnresolvedException(); assertThat(mvc.get().uri("/error/1")).hasFailed();
} }
@Test @Test
void hasUnresolvedException() { void hasFailedWithResolvedException() {
assertThat(mvc.get().uri("/error/1")).hasUnresolvedException(); assertThat(mvc.get().uri("/error/2")).hasFailed().hasStatus(HttpStatus.PAYMENT_REQUIRED);
} }
@Test @Test
void doesNotHaveUnresolvedExceptionWithUnresolvedException() { void doesNotHaveFailedWithoutException() {
assertThat(mvc.get().uri("/greet")).doesNotHaveFailed();
}
@Test
void doesNotHaveFailedWithUnresolvedException() {
assertThatExceptionOfType(AssertionError.class) assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(mvc.get().uri("/error/1")).doesNotHaveUnresolvedException()) .isThrownBy(() -> assertThat(mvc.get().uri("/error/1")).doesNotHaveFailed())
.withMessage("Expected request to succeed, but it failed"); .withMessage("Expected request to succeed, but it failed");
} }
@Test @Test
void hasUnresolvedExceptionWithoutUnresolvedException() { void doesNotHaveFailedWithResolvedException() {
assertThatExceptionOfType(AssertionError.class) assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(mvc.get().uri("/greet")).hasUnresolvedException()) .isThrownBy(() -> assertThat(mvc.get().uri("/error/2")).doesNotHaveFailed())
.withMessage("Expected request to succeed, but it failed");
}
@Test
void hasFailedWithoutException() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(mvc.get().uri("/greet")).hasFailed())
.withMessage("Expected request to fail, but it succeeded"); .withMessage("Expected request to fail, but it succeeded");
} }
@Test @Test
void unresolvedExceptionWithFailedRequest() { void failureWithUnresolvedException() {
assertThat(mvc.get().uri("/error/1")).unresolvedException() assertThat(mvc.get().uri("/error/1")).failure()
.isInstanceOf(ServletException.class) .isInstanceOf(ServletException.class)
.cause().isInstanceOf(IllegalStateException.class).hasMessage("Expected"); .cause().isInstanceOf(IllegalStateException.class).hasMessage("Expected");
} }
@Test @Test
void unresolvedExceptionWithSuccessfulRequest() { void failureWithResolvedException() {
assertThat(mvc.get().uri("/error/2")).failure()
.isInstanceOfSatisfying(ResponseStatusException.class, ex ->
assertThat(ex.getStatusCode()).isEqualTo(HttpStatus.PAYMENT_REQUIRED));
}
@Test
void failureWithoutException() {
assertThatExceptionOfType(AssertionError.class) assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(mvc.get().uri("/greet")).unresolvedException()) .isThrownBy(() -> assertThat(mvc.get().uri("/greet")).failure())
.withMessage("Expected request to fail, but it succeeded"); .withMessage("Expected request to fail, but it succeeded");
} }
@ -524,6 +544,11 @@ public class MockMvcTesterIntegrationTests {
throw new IllegalStateException("Expected"); throw new IllegalStateException("Expected");
} }
@GetMapping("/error/2")
public String two() {
throw new ResponseStatusException(HttpStatus.PAYMENT_REQUIRED);
}
@GetMapping("/error/validation/{id}") @GetMapping("/error/validation/{id}")
public String validation(@PathVariable @Size(max = 4) String id) { public String validation(@PathVariable @Size(max = 4) String id) {
return "Hello " + id; return "Hello " + id;

Loading…
Cancel
Save