Volkan Yazici opened SPR-12692 and commented
MockMvc fails to capture the message field of exceptions thrown by a controller; whereas, the same message gets captured perfectly well by the application server. That is, given the following controller:
@RestController
public class Controller {
@RequestMapping("/test")
public void create() {
throw new BadRequestException("it works");
}
}
such that BadRequestException is defined as:
@ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "bad request")
public class BadRequestException extends IllegalArgumentException {
public BadRequestException(String message) { super(message); }
}
the unit test shown below
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { Main.class })
@WebAppConfiguration
public class ControllerTest {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void testUserNewWithInvalidInput() throws Exception {
mockMvc.perform(get("/test")).andDo(print());
}
}
shows that MockMvc did not capture the response body:
...
MockHttpServletResponse:
Status = 400
Error message = bad request
Headers = {}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
However, the same controller works perfectly fine when run within a Servlet container:
$ curl -v http://localhost:8080/test
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /test HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 400 Bad Request
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Thu, 05 Feb 2015 13:40:46 GMT
< Connection: close
<
* Closing connection 0
{"timestamp":1423143646099,"status":400,"error":"Bad Request","exception":"com.vlkan.springtest.BadRequestException","message":"bad request","path":"/test"}
Affects: 4.1.4
0 votes, 6 watchers
Rossen Stoyanchev commented
I think the error message in the body is taken care of by Spring Boot which configures error mappings at the Servlet container level (see here) and since Spring MVC Test runs with a mock Servlet request/response, there is no such error mapping. I think the exception is handled instead by the ResponseStatusExceptionResolver (although I haven't verified this).
Given that this is Spring Boot provided error handling -- in other words it's not application logic, my recommendation is create at least one integration test (see Boot's documentation on @WebIntegrationTest) and stick to Spring MVC Test for your controller logic.
Volkan Yazici commented
Using an integration test indeed solves the problem, but I would feel happier if I could have done that using regular MockMvc unit tests too. Anyway, thanks for the tip.
Rossen Stoyanchev commented
Given there is no Servlet container involved, I'm afraid something like this is simply not in scope.
Alper Kanat commented
Hi @Rossen,
I'm affected by this problem as well. I wouldn't care for error response body since it's returning a proper HTTP status code which I can test against but I started to use Spring REST Docs and now I can't document the API because of this.
member sound commented
You might just use: .andReturn().getResolvedException().getMessage();
Most helpful comment
member sound commented
You might just use:
.andReturn().getResolvedException().getMessage();