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; @@ -89,12 +89,20 @@ import org.springframework.web.context.WebApplicationContext;
* <p>One main difference between {@link MockMvc} and {@code MockMvcTester} is
* that an unresolved exception is not thrown directly when using
* {@code MockMvcTester}. Rather an {@link MvcTestResult} is available with an
* {@linkplain MvcTestResult#getUnresolvedException() unresolved exception}
* which allows you to assert that a request failed unexpectedly:
* {@linkplain MvcTestResult#getUnresolvedException() unresolved exception}.
* Both resolved and unresolved exceptions are considered a failure that can
* be asserted as follows:
* <pre><code class="java">
* // perform a GET on /boom and assert the message for the the unresolved exception
* assertThat(mvc.get().uri("/boom")).hasUnresolvedException())
* .withMessage("Test exception");
* // perform a GET on /boom and assert the message for the the exception
* assertThat(mvc.get().uri("/boom")).hasFailed()
* .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>
*
* <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 @@ -59,13 +59,13 @@ public class MvcTestResultAssert extends AbstractMockHttpServletResponseAssert<M
}
/**
* Verify that the request failed with an unresolved exception, and
* return a new {@linkplain AbstractThrowableAssert assertion} object
* that uses the unresolved {@link Exception} as the object to test.
* Verify that the request has failed and return a new
* {@linkplain AbstractThrowableAssert assertion} object that uses the
* failure as the object to test.
*/
public AbstractThrowableAssert<?, ? extends Throwable> unresolvedException() {
hasUnresolvedException();
return Assertions.assertThat(this.actual.getUnresolvedException());
public AbstractThrowableAssert<?, ? extends Throwable> failure() {
hasFailed();
return Assertions.assertThat(getFailure());
}
/**
@ -137,20 +137,19 @@ public class MvcTestResultAssert extends AbstractMockHttpServletResponseAssert<M @@ -137,20 +137,19 @@ public class MvcTestResultAssert extends AbstractMockHttpServletResponseAssert<M
}
/**
* Verify that the request failed with an unresolved exception.
* @see #unresolvedException()
* Verify that the request has failed.
*/
public MvcTestResultAssert hasUnresolvedException() {
Assertions.assertThat(this.actual.getUnresolvedException())
public MvcTestResultAssert hasFailed() {
Assertions.assertThat(getFailure())
.withFailMessage("Expected request to fail, but it succeeded").isNotNull();
return this;
}
/**
* Verify that the request did not fail with an unresolved exception.
* Verify that the request has not failed.
*/
public MvcTestResultAssert doesNotHaveUnresolvedException() {
Assertions.assertThat(this.actual.getUnresolvedException())
public MvcTestResultAssert doesNotHaveFailed() {
Assertions.assertThat(getFailure())
.withFailMessage("Expected request to succeed, but it failed").isNull();
return this;
}
@ -184,6 +183,14 @@ public class MvcTestResultAssert extends AbstractMockHttpServletResponseAssert<M @@ -184,6 +183,14 @@ public class MvcTestResultAssert extends AbstractMockHttpServletResponseAssert<M
return this.myself;
}
@Nullable
private Throwable getFailure() {
Exception unresolvedException = this.actual.getUnresolvedException();
if (unresolvedException != null) {
return unresolvedException;
}
return this.actual.getMvcResult().getResolvedException();
}
@SuppressWarnings("NullAway")
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; @@ -53,6 +53,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@ -278,40 +279,59 @@ public class MockMvcTesterIntegrationTests { @@ -278,40 +279,59 @@ public class MockMvcTesterIntegrationTests {
class ExceptionTests {
@Test
void doesNotHaveUnresolvedException() {
assertThat(mvc.get().uri("/greet")).doesNotHaveUnresolvedException();
void hasFailedWithUnresolvedException() {
assertThat(mvc.get().uri("/error/1")).hasFailed();
}
@Test
void hasUnresolvedException() {
assertThat(mvc.get().uri("/error/1")).hasUnresolvedException();
void hasFailedWithResolvedException() {
assertThat(mvc.get().uri("/error/2")).hasFailed().hasStatus(HttpStatus.PAYMENT_REQUIRED);
}
@Test
void doesNotHaveUnresolvedExceptionWithUnresolvedException() {
void doesNotHaveFailedWithoutException() {
assertThat(mvc.get().uri("/greet")).doesNotHaveFailed();
}
@Test
void doesNotHaveFailedWithUnresolvedException() {
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");
}
@Test
void hasUnresolvedExceptionWithoutUnresolvedException() {
void doesNotHaveFailedWithResolvedException() {
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");
}
@Test
void unresolvedExceptionWithFailedRequest() {
assertThat(mvc.get().uri("/error/1")).unresolvedException()
void failureWithUnresolvedException() {
assertThat(mvc.get().uri("/error/1")).failure()
.isInstanceOf(ServletException.class)
.cause().isInstanceOf(IllegalStateException.class).hasMessage("Expected");
}
@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)
.isThrownBy(() -> assertThat(mvc.get().uri("/greet")).unresolvedException())
.isThrownBy(() -> assertThat(mvc.get().uri("/greet")).failure())
.withMessage("Expected request to fail, but it succeeded");
}
@ -524,6 +544,11 @@ public class MockMvcTesterIntegrationTests { @@ -524,6 +544,11 @@ public class MockMvcTesterIntegrationTests {
throw new IllegalStateException("Expected");
}
@GetMapping("/error/2")
public String two() {
throw new ResponseStatusException(HttpStatus.PAYMENT_REQUIRED);
}
@GetMapping("/error/validation/{id}")
public String validation(@PathVariable @Size(max = 4) String id) {
return "Hello " + id;

Loading…
Cancel
Save