spring boot单元测试之十五:用mockmvc测试返回异步结果的controller(spring boot 2.4.4)
一,演示项目相关信息
1,地址:
https://github.com/liuhongdi/asynctest
2, 功能:演示用mockmvc测试返回异步结果的controller
3,项目结构:如图:
说明:刘宏缔的架构森林是一个专注架构的博客,
网站:https://blog.imgtouch.com
本文: https://blog.imgtouch.com/index.php/2023/05/27/spring-boot-dan-yuan-ce-shi-zhi-shi-wu-yong-mockmvc-ce-shi/
对应的源码可以访问这里获取: https://github.com/liuhongdi/
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,java代码
1,controller/HomeController.java
@RestController @RequestMapping("/home") public class HomeController { @Autowired private HelloService helloService; /** * 异步方法 * @return */ @RequestMapping("/callable") public Callable<String> deferredResult() throws Exception { System.out.println("控制层执行线程:" + Thread.currentThread().getName()); return new Callable<String>() { @Override public String call() throws Exception { System.out.println("异步执行线程:" + Thread.currentThread().getName()); String str = helloService.task2(); Thread.sleep(1000); return str; } }; } /** * 异步方法 * @return */ @RequestMapping("/async") public String getAsynHello(){//异步 String s = helloService.asynchSayHello(); System.out.println(s); return s; } /** * 同步方法 * * @return */ @GetMapping("/sync") public String getSyncHello(){//异步 String s = helloService.synchSayHello();return s; } }
2,service/HelloService.java
@Service public class HelloService { @Resource private SleepService sleepService; //callable中调用的方法 public String task2 () throws Exception { System.out.println("异步:线程名: " +Thread.currentThread().getName()); Thread.sleep(2000); return "this is callable"; } //同步方法 public String synchSayHello() { try { //sleepService.syncSleep(); System.out.println("同步:线程名: " +Thread.currentThread().getName()); Thread.sleep(3000); return "this is sync"; } catch (InterruptedException e) { e.printStackTrace(); return "error"; } } //调用异步的asyncsleep方法 public String asynchSayHello() { try { System.out.println("异步:线程名1: " +Thread.currentThread().getName()); sleepService.asyncSleep(); return "this is async"; } catch (Exception e) { e.printStackTrace(); return "error"; } } }
3,service/SleepService.java
@Service public class SleepService { //异步方法 @Async public void asyncSleep() throws Exception{ System.out.println("异步:线程名2: " +Thread.currentThread().getName()); Thread.sleep(3000); } }
4,controller/HomeControllerTest.java
@AutoConfigureMockMvc @SpringBootTest class HomeControllerTest { @Autowired private MockMvc mockMvc; @Test @DisplayName("测试callable正确执行返回字符串") void callableResult() throws Exception { /* MvcResult result = mockMvc.perform(get("/home/callable")) //执行请求 .andExpect(request().asyncStarted()) //.andExpect(request().asyncResult(CoreMatchers.instanceOf(User.class))) //默认会等10秒超时 .andReturn(); mockMvc.perform(asyncDispatch(result)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id").value(1)); */ MvcResult mvcResult = mockMvc.perform(get("/home/callable")) .andExpect(request().asyncStarted()) .andReturn(); mockMvc.perform(asyncDispatch(mvcResult)) .andExpect(status().isOk()) .andExpect(content().string("this is callable")); } @Test @DisplayName("测试callable不正确执行返回字符串") void deferredResult() throws Exception { MvcResult mvcResult = mockMvc.perform(get("/home/callable") .contentType(MediaType.APPLICATION_FORM_URLENCODED)) .andReturn(); String content = mvcResult.getResponse().getContentAsString(); assertThat(content, equalTo("")); } @Test @DisplayName("测试async返回字符串") void getAsynHello() throws Exception { MvcResult mvcResult = mockMvc.perform(get("/home/async") .contentType(MediaType.APPLICATION_FORM_URLENCODED)) .andReturn(); String content = mvcResult.getResponse().getContentAsString(); assertThat(content, equalTo("this is async")); } @Test @DisplayName("测试sync返回字符串") void getSyncHello() throws Exception { MvcResult mvcResult = mockMvc.perform(get("/home/sync") .contentType(MediaType.APPLICATION_FORM_URLENCODED)) .andReturn(); String content = mvcResult.getResponse().getContentAsString(); assertThat(content, equalTo("this is sync")); } }
三,测试效果
四,备注
1,controller在返回callable结果时,mockmvc的请求结果会为空
2,@Async注解需要添加到另一个类中的方法上调用,
不能调用本类中的async方法,
否则会不生效
五,查看spring boot的版本:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.4.4)