如何对返回Mono类型的方法进行JUnit测试并获取响应体
问题原因
返回Mono类型的接口在Spring MVC中会触发异步Servlet处理流程,默认MockMvc的perform方法仅等待控制器方法执行完成,不会等待异步结果处理、写入响应体的全流程,因此你会看到响应体为空,目标值仅存在于Async异步结果中。
你额外添加的StepVerifier仅用于验证Service层Mono方法的返回值,和Controller层接口返回响应的流程无关,不会影响MockMvc的测试结果。
解决方案
调整MockMvc的调用逻辑,等待异步处理完成后再执行断言即可,修改后的测试代码如下:
@WebMvcTest(DataController.class) public class DataMockTest { @Autowired private MockMvc mockMvc; @MockBean private Service service; @Test public void getDataTest() throws Exception { Mono<String> strMono = Mono.just("Single Item Only"); when(service.getData("DATA")).thenReturn(strMono); // 验证Service层返回 StepVerifier.create(service.getData("DATA")) .assertNext(data -> { assertNotNull(data); assertEquals("Single Item Only", data); }).verifyComplete(); // 第一步:执行请求,拿到异步结果 MvcResult mvcResult = this.mockMvc.perform(get("/some/rest/toget/data") .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andExpect(request().asyncStarted()) .andReturn(); // 阻塞等待异步处理完成,再执行分发写入响应 this.mockMvc.perform(asyncDispatch(mvcResult)) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().string("Single Item Only")); // 直接断言响应体内容 } }
可选优化方案
如果你的项目是Spring WebFlux全栈应用,更推荐使用@WebFluxTest搭配WebTestClient测试,无需手动处理异步逻辑,写法更简洁:
@WebFluxTest(DataController.class) public class DataMockTest { @Autowired private WebTestClient webTestClient; @MockBean private Service service; @Test public void getDataTest() { Mono<String> strMono = Mono.just("Single Item Only"); when(service.getData("DATA")).thenReturn(strMono); webTestClient.get().uri("/some/rest/toget/data") .accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk() .expectBody(String.class) .isEqualTo("Single Item Only"); } }
注意事项
你原有代码中StepVerifier调用的service.getDATA("DATA")和mock的service.getData("DATA")大小写不一致,请确认方法名匹配,避免mock不生效的问题。
内容的提问来源于stack exchange,提问作者JayC
相关产品推荐
相关产品推荐

