如何在ApplicationReadyEvent前Mock对象?Spring定时任务测试难题
解决方案
方案1:替换初始化时机为@PostConstruct
将原本监听ApplicationReadyEvent的初始化逻辑,改为使用@PostConstruct注解。这个注解的执行时机是当前Bean的依赖注入完成后、Bean被放入Spring容器前,测试中通过@MockBean声明的RestTemplate会提前完成注入,避免空指针异常:
@PostConstruct private void init() { if(auth != null){ auth.getToken(); instanceURL = token.getInstanceUrl(); } if(urlUtils !=null){ urlUtils.setServiceUrl(); } }
方案2:测试中手动控制初始化流程
把初始化方法的访问修饰符改为包私有(移除private),测试时先配置好Mock行为,再手动触发初始化,同时禁用自动触发的事件初始化:
客户端类调整
@EventListener(ApplicationReadyEvent.class) void init() { if(auth != null){ auth.getToken(); instanceURL = token.getInstanceUrl(); } if(urlUtils !=null){ urlUtils.setServiceUrl(); } }
测试类示例
@SpringBootTest public class ClientTest { @Autowired private Client client; @MockBean private RestTemplate restTemplate; // 如果auth是客户端内部类,可给客户端添加包私有方法获取auth实例 @Autowired private Auth auth; @BeforeEach void setUp() { // 先配置Mock的响应行为 when(restTemplate.exchange(anyString(), any(HttpMethod.class), any(), eq(TokenResponse.class))) .thenReturn(new ResponseEntity<>(new TokenResponse(), HttpStatus.OK)); // 禁用自动事件触发的初始化(Mock事件发布器) @MockBean private ApplicationEventPublisher eventPublisher; // 手动调用初始化方法 client.init(); } @Test void scheduledTaskTest() { // 执行测试逻辑 } }
方案3:强制指定Bean初始化顺序
通过@DependsOn注解确保RestTemplate的Mock实例优先于客户端Bean初始化,保证初始化逻辑执行时Mock已就绪:
测试配置类
@TestConfiguration public class TestConfig { @Bean("mockRestTemplate") @Primary public RestTemplate mockRestTemplate() { return Mockito.mock(RestTemplate.class); } }
客户端类添加依赖注解
@Component @DependsOn("mockRestTemplate") public class Client { // 原有代码... @EventListener(ApplicationReadyEvent.class) private void init() { // 原有初始化逻辑 } }
测试类
@SpringBootTest @Import(TestConfig.class) public class ClientTest { @Autowired private Client client; @Autowired private RestTemplate restTemplate; @BeforeEach void setUp() { // 配置Mock行为 when(restTemplate.exchange(...)).thenReturn(...); } // 测试方法 }
方案4:实现SmartInitializingSingleton接口
让客户端类实现SmartInitializingSingleton接口,其afterSingletonsInstantiated()方法会在所有单例Bean初始化完成后执行,这个时机晚于依赖注入、早于ApplicationReadyEvent,测试Mock已完全注入:
@Component public class Client implements SmartInitializingSingleton { // 原有属性和方法 @Override public void afterSingletonsInstantiated() { if(auth != null){ auth.getToken(); instanceURL = token.getInstanceUrl(); } if(urlUtils !=null){ urlUtils.setServiceUrl(); } } }
内容的提问来源于stack exchange,提问作者Tocchetto
相关产品推荐
相关产品推荐

