用于DeferredResult的Spring MVC单元测试不会调用超时回调 [英] Spring MVC unit test for DeferredResult doesn't call timeout callback

查看:343
本文介绍了用于DeferredResult的Spring MVC单元测试不会调用超时回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Java 7上使用Spring 4.3.18和Spring Boot 1.5.14.

I'm using Spring 4.3.18 and Spring Boot 1.5.14 on Java 7.

我正在实现RestController端点,该端点返回带有超时回调的DeferredResult.我正在尝试为超时回调编写单元测试,但无法获得MockMvc单元测试来调用超时回调.

I'm implementing a RestController endpoint which returns a DeferredResult with a timeout callback. I'm trying to write a unit test for the timeout callback, but I can't get a MockMvc unit test to call the timeout callback.

为了测试,我写了这个端点:

For the sake of testing, I wrote this endpoint:

@PostMapping("/test")
public DeferredResult<String>
testit() {
    logger.info("testit called");
    final DeferredResult<String> rv = new DeferredResult<>(1000L);
    rv.onTimeout(new Runnable() {
        @Override
        public void run() {
            logger.info("run called");
            rv.setResult("timed out");
        }
    });
    return rv;
}

和此单元测试:

@Autowired
private MockMvc mockMvc;

@Test
public void testTest() throws Exception {
    MvcResult result = mockMvc.perform(post("/rest/tasks/test"))
        .andExpect(request().asyncStarted())
        .andReturn();
    result.getAsyncResult(1500);
    mockMvc.perform(asyncDispatch(result))
        .andExpect(status().isOk())
        ;
}

(对result.getAsyncResult(1500)的调用基于 https://jira.spring.io/browse/SPR-16869 )

运行此命令时,会调用testit()端点,并且在1500 ms延迟后,我收到一个异常,抱怨从未调用setResult().超时处理程序未调用:

When I run this, the testit() endpoint is called, and after a 1500 ms delay, I get an exception complaining that setResult() was never called. The timeout handler isn't invoked:

java.lang.IllegalStateException: Async result for handler [public org.springframework.web.context.request.async.DeferredResult<java.lang.String> my.package.TasksController.testit()] was not set during the specified timeToWait=1500
    at org.springframework.test.web.servlet.DefaultMvcResult.getAsyncResult(DefaultMvcResult.java:135)
    at my.package.TasksControllerTest.testTest(TasksControllerTest.java:200)

2517 [main] INFO my.package.TasksController - testit called

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /rest/tasks/test
       Parameters = {}
          Headers = {}

Handler:
             Type = my.package.TasksController
           Method = public org.springframework.web.context.request.async.DeferredResult<java.lang.String> my.package.TasksController.testit()

Async:
    Async started = true
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = {}
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
4037 [Thread-2] INFO org.springframework.web.context.support.GenericWebApplicationContext - Closing org.springframework.web.context.support.GenericWebApplicationContext@6ea91f6: startup date [Thu Jul 26 19:44:31 EDT 2018]; root of context hierarchy

我该怎么做才能使测试框架在DeferredResult上调用超时处理程序?

What do I need to do to make the test framework invoke the timeout handler on the DeferredResult?

推荐答案

似乎可以在单元测试中创建一个合成超时,如下所示:

It seems it's possible to create a synthetic timeout in the unit test like this:

@Test
public void testTest() throws Exception {
    MvcResult result = mockMvc.perform(post("/rest/tasks/test"))
        .andExpect(request().asyncStarted())
        .andReturn();
    // Trigger a timeout on the request
    MockAsyncContext ctx = (MockAsyncContext) result.getRequest().getAsyncContext();
    for (AsyncListener listener : ctx.getListeners()) {
        listener.onTimeout(null);
    }
    mockMvc.perform(asyncDispatch(result))
        .andExpect(status().isOk())
        ;
}

访问请求的异步侦听器并调用onTimeout()将导致调用DeferredRequest的超时回调.

Accessing the request's async listeners and calling onTimeout() will result in calling the DeferredRequest's timeout callback.

我的问题中对result.getAsyncResult(1500)的调用对于此测试是多余的,因为asyncDispatch()仍会调用getAsyncResult().

The call to result.getAsyncResult(1500) from my question is redundant for this test, because asyncDispatch() will call getAsyncResult() anyway.

这篇关于用于DeferredResult的Spring MVC单元测试不会调用超时回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆