Mockito @MockBean在新线程中二次调用失效问题排查
问题分析
你遇到的@MockBean在新线程中第二次调用返回null的问题,根源在于Spring Boot 1.5.x版本结合JUnit 4时,@MockBean生成的代理对象依赖线程局部上下文存储mock存根。当在主线程设置mock行为后,新线程第一次调用能读取到存根,但第二次调用时,线程上下文的mock状态已丢失,导致返回默认值null。
解决方案
针对这个问题,有以下几种可行的解决方式:
方案1:在新线程内设置mock存根
把mock行为的设置逻辑移到新线程内部,确保存根在当前线程上下文生效:
@Test public void testInNewThread_work() { Thread t = new Thread(new Runnable() { public void run() { // 在新线程内设置mock行为 DemoServiceMock.mockdoSomething(demoService); // 两次调用都会返回预期值 String result = demoService.doSomething("324234"); System.out.println("return in thread: " + result); String result2 = demoService.doSomething("324234"); System.out.println("return2 in thread: " + result2); } }); t.start(); // 等待线程执行完成,避免测试提前结束 try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }
方案2:手动创建mock并注入Spring上下文
放弃@MockBean,手动创建Mockito mock实例,通过@Primary标记优先注入,这样mock是全局线程安全的:
@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = DemoApplication.class) public class DemoApplicationTests { @Autowired protected DemoService demoService; // 手动创建mock并标记为优先注入的Bean @Bean @Primary public DemoService demoServiceMock() { return Mockito.mock(DemoService.class); } @Test public void testInNewThread_work() { DemoServiceMock.mockdoSomething(demoService); Thread t = new Thread(new Runnable() { public void run() { String result = demoService.doSomething("324234"); System.out.println("return in thread: " + result); String result2 = demoService.doSomething("324234"); System.out.println("return2 in thread: " + result2); } }); t.start(); try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } } }
方案3:升级Spring Boot版本
Spring Boot 1.5.x属于老旧版本,后续2.x+版本已修复@MockBean在多线程场景下的线程上下文问题。如果项目允许,建议升级到Spring Boot 2.x及以上版本,无需修改代码即可解决该问题。
补充说明
原测试方法testInNewThread_notWork未等待新线程执行完成,可能导致测试提前结束,无法看到完整输出结果,建议添加t.join()确保线程执行完毕。
内容的提问来源于stack exchange,提问作者stonez08
相关产品推荐
相关产品推荐

