Spring MockMvc and async controller's HTTP status code
当我的控制器具有异步servlet性质时,如何在MockMvc中验证/测试500个内部服务器错误?
我正在为我的REST端点编写单元测试用例,作为测试用例的一部分,我需要验证服务器是否将500内部错误作为http代码发送并带有适当的错误消息。
这是我基于Spring Boot的应用程序:
(为了更好的可读性,省略了所有导入)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | @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); } } |
这是我的MovkMvc JUnit测试用例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | @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(); } } } |
下面是控制台打印的内容:
1 2 3 4 5 | 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 |
从上面的日志中可以明显看出MockMvc返回http状态代码为200而不是500。错误消息很好。
当我使用Chrome邮递员调用端点时,在图像中看到500个内部服务器错误
您必须执行异步调度并随后测试状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 | @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(); } |
处理同步和异步请求的自定义
1 2 3 4 5 6 7 8 9 10 | 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; } } |
此处提供示例的更长答案
以下是使用方法
的有效示例(Groovy Spock规范)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import static org.hamcrest.core.IsNull.notNullValue import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.* @ContextConfiguration(classes = [MyConfig]) @WebAppConfiguration class MyControllerComponentSpec extends Specification { @Autowired WebApplicationContext webApplicationContext MockMvc endpoint def setup() { endpoint = MockMvcBuilders.webAppContextSetup(webApplicationContext).build() } ResultActions asyncPerform(MockHttpServletRequestBuilder builder) throws Exception { ResultActions resultActions = endpoint.perform(builder); asyncDispatch(resultActions.andExpect(request() .asyncResult(notNullValue())) .andReturn())); } def"accepts valid request and responds with 200 status code and response body"() { when: def response = asyncPerform(post("/my_async_endpoint") .content("""{"correlationID":"fe5d1699-20e3-4502-bf51-b947e6b9e51a"}""") .header("Content-Type","application/json")) .andDo(print()) then: response.andExpect(status().is(200)) .andExpect(jsonPath("body.correlationID").value("fe5d1699-20e3-4502-bf51-b947e6b9e51a")) } } |