How do i validate/test the 500 internal server error in MockMvc, when my controller is of Async servlet nature?
I am writing unit test cases for my REST endpoint as part of a test cases i need to validate that the server sends 500 internal error as http code and with appropriate error message.
Here is my spring boot based app: (all imports are omitted for better readability)
@RestController
@RequestMapping("/user")
@EnableAutoConfiguration
@SpringBootApplication
public class App 
{
    @RequestMapping(method = RequestMethod.GET, value = "/{name}", 
            produces = MediaType.APPLICATION_JSON_VALUE)
    private DeferredResult<String> greetByJson(@PathVariable("name") final String name){
        DeferredResult<String> dResult = new DeferredResult<String>();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    dResult.setErrorResult(new RuntimeException("Boom!!! time for Internal server error"));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        return dResult;
    }
    public static void main( String[] args )
    {
        SpringApplication.run(App.class);
    }
}
Here is my MovkMvc JUnit test cases:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MockServletContext.class)
@WebAppConfiguration
public class AppTest {
    private final MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new App())
            .build();
    @Test
    public void testAsyncInternalServerError() {
        try {
            MvcResult mvcResult = mockMvc.perform(
                    get("/user/naveen").accept(MediaType.APPLICATION_JSON_VALUE))
                    .andExpect(request().asyncStarted())
                    .andReturn();
            System.out.println("Http Response Content = " + mvcResult.getAsyncResult());
            System.out.println("Http Response Status Code = " + mvcResult.getResponse().getStatus());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Below is the console prints:
2015-08-08 18:11:51.494  INFO 10224 --- [           main] o.s.w.c.s.GenericWebApplicationContext   : Refreshing org.springframework.web.context.support.GenericWebApplicationContext@a82c5f1: startup date [Sat Aug 08 18:11:51 IST 2015]; root of context hierarchy
2015-08-08 18:11:51.526  INFO 10224 --- [           main] o.e.j.i.junit.runner.RemoteTestRunner    : Started RemoteTestRunner in 0.258 seconds (JVM running for 1.131)
Http Response Content = java.lang.RuntimeException: Boom!!! time for Internal server error
Http Response Status Code = 200
2015-08-08 18:11:56.584  INFO 10224 --- [       Thread-1] o.s.w.c.s.GenericWebApplicationContext   : Closing org.springframework.web.context.support.GenericWebApplicationContext@a82c5f1: startup date [Sat Aug 08 18:11:51 IST 2015]; root of context hierarchy
From the above log its evident that MockMvc returns http status code as 200 not 500. The error message is just fine.
Where as when i invoke the end point using Chrome postman, i see 500 internal server error as attached in the image
You must perform async dispatch and test the status afterwards:
@Test
public void testMethod() throws Exception {
    MvcResult mvcResult = mockMvc.perform(get("/your/endpoint"))
            .andExpect(request().asyncStarted())
            .andExpect(request().asyncResult(notNullValue()))
            .andReturn();
    mockMvc.perform(asyncDispatch(mvcResult))
            .andExpect(status().isInternalServerError())
            .andReturn();
}
                        Custom perform helper method that handles both sync and async request:
ResultActions perform(MockHttpServletRequestBuilder builder) throws Exception {
    ResultActions resultActions = mockMvc.perform(builder);
    if (resultActions.andReturn().getRequest().isAsyncStarted()) {
      return mockMvc.perform(asyncDispatch(resultActions
          .andExpect(request().asyncResult(anything()))
          .andReturn()));
    } else {
      return resultActions;
    }
}
Longer answer with example here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With