异步请求

本节展示了如何单独使用 MockMvc 来测试异步请求处理。 如果通过 WebTestClient 使用 MockMvc,则无需做任何特殊处理即可使 异步请求工作,因为 WebTestClient 会自动执行本节中描述的操作。

Servlet 异步请求(Spring MVC 中支持)的工作原理是退出 Servlet 容器线程,并允许应用程序异步计算 响应,之后进行异步调度以在 Servlet 容器线程上完成处理。

在 Spring MVC Test 中,可以通过首先断言生成的异步值,然后手动执行异步调度,最后验证响应来测试异步请求。 下面是一个针对返回 DeferredResultCallable 或 Reactor Mono 等响应式类型的控制器方法的示例测试:

Java
// static import of MockMvcRequestBuilders.* and MockMvcResultMatchers.*

@Test
void test() throws Exception {
	MvcResult mvcResult = this.mockMvc.perform(get("/path"))
			.andExpect(status().isOk()) [id="CO1-1"]1
			.andExpect(request().asyncStarted()) [id="CO1-2"]2
			.andExpect(request().asyncResult("body")) [id="CO1-3"]3
			.andReturn();

	this.mockMvc.perform(asyncDispatch(mvcResult)) [id="CO1-4"]4
			.andExpect(status().isOk()) [id="CO1-5"]5
			.andExpect(content().string("body"));
}
<1>  检查响应状态是否未改变
<1>  异步处理必须已开始
<1>  等待并断言异步结果
<1>  手动执行 ASYNC 调度(因为没有正在运行的容器)
<1>  验证最终响应
Kotlin
@Test
fun test() {
	var mvcResult = mockMvc.get("/path").andExpect {
		status { isOk() } [id="CO2-1"][id="CO1-1"][id="CO2-1"](1)
		request { asyncStarted() } [id="CO2-2"][id="CO1-2"][id="CO2-2"](2)
		// TODO Remove unused generic parameter
		request { asyncResult<Nothing>("body") } [id="CO2-3"][id="CO1-3"][id="CO2-3"](3)
	}.andReturn()


	mockMvc.perform(asyncDispatch(mvcResult)) [id="CO2-4"][id="CO1-4"][id="CO2-4"](4)
			.andExpect {
				status { isOk() } [id="CO2-5"][id="CO1-5"][id="CO2-5"](5)
				content().string("body")
			}
}
<1>  检查响应状态是否未改变
<1>  异步处理必须已开始
<1>  等待并断言异步结果
<1>  手动执行 ASYNC 调度(因为没有正在运行的容器)
<1>  验证最终响应