一起测试Spring asyncResult()和jsonPath()


问题内容

我正在使用一个宁静的URL来启动一个长期运行的后端进程(它通常在cron计划中,但是我们希望能够手动启动它)。

下面的代码有效,当我手动测试时,我会在浏览器中看到结果。

@ResponseBody
@RequestMapping(value = "/trigger/{jobName}", method = RequestMethod.GET)
public Callable<TriggerResult> triggerJob(@PathVariable final String jobName) {

    return new Callable<TriggerResult>() {
        @Override
        public TriggerResult call() throws Exception {
            // Code goes here to locate relevant job and kick it off, waiting for result
            String message = <result from my job>;
            return new TriggerResult(SUCCESS, message);
        }
    };
}

当我不Callable使用此代码进行测试时,便使用了下面的代码,并且所有代码都可以正常工作(我更改了预期的错误消息以简化发布)。

mockMvc.perform(get("/trigger/job/xyz"))
    .andExpect(status().isOk())
    .andDo(print())
    .andExpect(jsonPath("status").value("SUCCESS"))
    .andExpect(jsonPath("message").value("A meaningful message appears"));

当我添加了Callable但是它不起作用。我也在下面尝试过,但是没有用。其他人成功了吗?

mockMvc.perform(get("/trigger/job/xyz"))
    .andExpect(status().isOk())
    .andDo(print())
    .andExpect(request().asyncResult(jsonPath("status").value("SUCCESS")))
    .andExpect(request().asyncResult(jsonPath("message").value("A meaningful message appears")));

以下是我的print()的相关部分。在这种情况下,mockMvc似乎无法正确解开Json(即使它在我的浏览器中也有效)?当我不这样做时,我会Callable看到完整的JSON。

MockHttpServletRequest:
     HTTP Method = GET
     Request URI = /trigger/job/xyz
      Parameters = {}
         Headers = {}

         Handler:
            Type = foo.bar.web.controller.TriggerJobController
          Method = public java.util.concurrent.Callable<foo.bar.myproject.web.model.TriggerResult> foo.bar.myproject.web.controller.TriggerJobController.triggerJob(java.lang.String)

           Async:
 Was async started = true
      Async result = foo.bar.myproject.web.model.TriggerResult@67aa1e71


Resolved Exception:
            Type = null

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

        FlashMap:

MockHttpServletResponse:
          Status = 200
   Error message = null
         Headers = {}
    Content type = null
            Body = 
   Forwarded URL = null
  Redirected URL = null
         Cookies = []

问题答案:

Bud的回答确实帮助我指出了正确的方向,但是由于它没有等待异步结果,因此并没有奏效。自发布此问题以来,spring-mvc-
showcase示例(https://github.com/SpringSource/spring-mvc-
showcase
)已更新。

看起来在调用的第一部分中,当您检索MvcResult时,您需要在asyncResult()上声明,对于JSON
pojo映射,您需要在实际的类型本身(而不是JSON)上声明。所以我需要在Bud的答案中添加第三行,然后其余的就可以了。

MvcResult mvcResult = this.mockMvc.perform(get("/trigger/job/xyz"))
    .andExpect(request().asyncStarted())
    .andExpect(request().asyncResult(instanceOf(TriggerResult.class)))
    .andReturn();

this.mockMvc.perform(asyncDispatch(mvcResult))
    .andExpect(status().isOk())
    .andExpect(content().contentType(MediaType.APPLICATION_JSON))
    .andExpect(jsonPath("status").value("SUCCESS"))
    .andExpect(jsonPath("message").value("A meaningful message appears"));

注意:
instanceOf()org.hamcrest.CoreMatchers.instanceOf。要访问Hamcrest库,请包含最新的hamcrest- libraryjar。

对于行家…

    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-library</artifactId>
        <version>LATEST VERSION HERE</version>
        <scope>test</scope>
    </dependency>