我正在实施long polling as per the Spring blog from some time ago。
这里我的转换方法具有与以前相同的响应签名,但它现在使用长轮询而不是立即响应:
private Map<String, DeferredResult<ResponseEntity<?>>> requests = new ConcurrentHashMap<>();
@RequestMapping(value = "/{uuid}", method = RequestMethod.GET)
public DeferredResult<ResponseEntity<?>> poll(@PathVariable("uuid") final String uuid) {
// Create & store a new instance
ResponseEntity<?> pendingOnTimeout = ResponseEntity.accepted().build();
DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>(TWENTYFIVE_SECONDS, pendingOnTimeout);
requests.put(uuid, deferredResult);
// Clean up poll requests when done
deferredResult.onCompletion(() -> {
requests.remove(deferredResult);
});
// Set result if already available
Task task = taskHolder.retrieve(uuid);
if (task == null)
deferredResult.setResult(ResponseEntity.status(HttpStatus.GONE).build());
else
// Done (or canceled): Redirect to retrieve file contents
if (task.getFutureFile().isDone())
deferredResult.setResult(ResponseEntity.created(RetrieveController.uri(uuid)).build());
// Return result
return deferredResult;
}
特别是当请求花费太长时间(我之前立即返回)时,我想返回pendingOnTimeout
响应,以防止代理切断请求。
现在我觉得我已经按原样运行,但是我想编写一个证明这一点的单元测试。但是,我使用MockMvc(通过webAppContextSetup)的所有尝试都无法为我提供断言我获得accepted
标头的方法。例如,当我尝试以下内容时:
@Test
public void pollPending() throws Exception {
MvcResult result = mockMvc.perform(get("/poll/{uuid}", uuidPending)).andReturn();
mockMvc.perform(asyncDispatch(result))
.andExpect(status().isAccepted());
}
我得到以下stacktrace:
java.lang.IllegalStateException:处理程序的异步结果[public org.springframework.web.context.request.async.DeferredResult>在指定的timeToWait = 25000期间未设置nl.bioprodict.blast.api.PollController.poll(java.lang.String)] 在org.springframework.util.Assert.state(Assert.java:392) 在org.springframework.test.web.servlet.DefaultMvcResult.getAsyncResult(DefaultMvcResult.java:143) 在org.springframework.test.web.servlet.DefaultMvcResult.getAsyncResult(DefaultMvcResult.java:120) 在org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch(MockMvcRequestBuilders.java:235) 在nl.bioprodict.blast.docs.PollControllerDocumentation.pollPending(PollControllerDocumentation.java:53) ...
与此相关的Spring框架测试,我发现它们似乎都使用了嘲弄它:https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/test/java/org/springframework/web/context/request/async/WebAsyncManagerTimeoutTests.java
如何测试DeferredResult timeoutResult的正确处理?
答案 0 :(得分:7)
在我的情况下,经过Spring源代码并设置超时(10000毫秒)并获得异步结果后,我就解决了它,as;
mvcResult.getRequest().getAsyncContext().setTimeout(10000);
mvcResult.getAsyncResult();
我的整个测试代码是;
MvcResult mvcResult = this.mockMvc.perform(
post("<SOME_RELATIVE_URL>")
.contentType(MediaType.APPLICATION_JSON)
.content(<JSON_DATA>))
***.andExpect(request().asyncStarted())***
.andReturn();
***mvcResult.getRequest().getAsyncContext().setTimeout(10000);***
***mvcResult.getAsyncResult();***
this.mockMvc
.perform(asyncDispatch(mvcResult))
.andDo(print())
.andExpect(status().isOk());
希望有所帮助......
答案 1 :(得分:4)
我ran across this problem使用Spring 4.3,并设法找到一种从单元测试中触发超时回调的方法。在获得MvcResult
之后和调用asyncDispatch()
之前,您可以插入如下代码:
MockAsyncContext ctx = (MockAsyncContext) mvcResult.getRequest().getAsyncContext();
for (AsyncListener listener : ctx.getListeners()) {
listener.onTimeout(null);
}
请求的异步侦听器之一将调用DeferredResult
的超时回调。
因此您的单元测试将如下所示:
@Test
public void pollPending() throws Exception {
MvcResult result = mockMvc.perform(get("/poll/{uuid}", uuidPending)).andReturn();
MockAsyncContext ctx = (MockAsyncContext) result.getRequest().getAsyncContext();
for (AsyncListener listener : ctx.getListeners()) {
listener.onTimeout(null);
}
mockMvc.perform(asyncDispatch(result))
.andExpect(status().isAccepted());
}