Reputation: 12212
I would like to test the message of the DefaultErrorAttributes
returned when the REST controller returns a Bad Request. The controller throws a QueryException
which is handled by a ControllerAdvice
.
@ControllerAdvice
public class ErrorHandlingControllerAdvice {
@ExceptionHandler(QueryException.class)
void onApplicationException(QueryException e, HttpServletResponse response) throws IOException {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
}
}
The response:
{
"timestamp": "2018-12-04T17:05:37.403+0000",
"status": 400,
"error": "Bad Request",
"message": "Query error message",
"path": "/search/v1/query/x"
}
The WebMvcTest
test loads the ControllerAdvice
in the context, the exception is correctly handled (I checked with a breakpoint). The issue is that the content of the response is empty. The assertion content().string("")
passed whereas it should not.
@SpringJUnitConfig({QueryResource.class, ErrorHandlingControllerAdvice.class})
@WebMvcTest(QueryResource.class)
public class QueryResourceTest {
@Autowired
private MockMvc mvc;
@Test
public void testQuery() throws Exception {
String xmlQuery = ResourceHelper.loadResource("/rest/query.xml");
this.mvc.perform(post("/v1/query/test")
.contentType(MediaType.APPLICATION_XML)
.content(xmlQuery))
.andExpect(status().isBadRequest())
.andExpect(content().string(""))
.andExpect(jsonPath("$.message", is("Query error message")));
}
}
Upvotes: 4
Views: 2362
Reputation: 14165
This: I would like to test the message of ... You have done successfully. So I believe the question is "why doesn't this send the response back so I can read it?"
What you are doing is mixing the idea of a Unit Test with the desire to gain the results as if it were and integration test.
The obvious reason this is happening has to do with the difference between the runtime environment and test environment. This is because in the runtime environment you have a servlet container that is dispatching the response. Here, MockMVC is running without the use of a servlet container. That means there is no mechanism for the DefaultErrorAttributes
to get dispatched and propagate back as a response.
Here is a support request and detailed explanation of why this is doing what it is doing:
MockMvc doesn't use spring-boot's mvc exception handler
That GitHub issue also points to a MockMVC SPR addressing the issue:
Actually support request forwarding in MockRequestDispatcher
To perform integration the type of test you've constructed, you'll need to start up the Spring Boot application context and start up the server. To do that simply rewicker your test Class thus:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class QueryResourceTest {
// ...
}
The @SpringBootTest annotation, using the WebEnvironment setting is used here to start the server. Other changes will likely be necessary as you move more into integration testing and away from unit testing with MockMVC.
Upvotes: 3