Spring Boot集成测试:如何在应用上下文启动前Mock @Service服务
解决方案
问题根因
- Mock不生效核心是两个初始化时机冲突:
- Spring Boot定时任务在应用上下文初始化完成后立刻执行,此时测试类的Mock/桩方法还没完成配置,作业运行时调用的是原始对象
- Spring Batch组件初始化优先级高于测试自定义配置,你注入到Batch配置类的RepositoryFactory在Mock创建前就已经被初始化完成,后续Mock不会覆盖已经注入的实例
- WireMock失效是因为你没有修改微服务Y的调用地址配置到WireMock监听端口,同时端口/网络冲突导致SFTP连接异常。
分步修复方案
1. 禁用测试环境自动定时任务
在你的application-test.properties中添加配置,关闭定时任务自动触发,避免作业提前执行:
spring.task.scheduling.enabled=false
如果你的定时任务是自定义配置的,可以给@Scheduled注解的类加上@ConditionalOnProperty(name = "task.scheduling.enabled", havingValue = "true", matchIfMissing = true),测试环境默认关闭即可。
2. 正确加载Mock配置类
你之前的测试类@ContextConfiguration只引入了JsonHalConfig,没有加载你的自定义Mock配置,修改测试类注解:
@ContextConfiguration(classes = {JsonHalConfig.class, RepositoryTestConfig.class})
你的第一个RepositoryTestConfig配置是可用的,保留@Primary注解确保Mock的工厂优先被注入。
3. 测试中手动触发Spring Batch作业
不要依赖定时任务触发,直接在测试类中注入作业启动器和作业实例,待上下文完全初始化、Mock配置完成后手动触发作业:
在测试类中添加注入:
@Autowired private JobLauncher jobLauncher; @Autowired private Job importCsvJob; // 替换为你实际的导入作业Bean名
修改测试方法手动触发作业:
@Test public void testImportFlow() throws Exception { // 构造作业参数,和定时任务传的参数保持一致 JobParameters jobParameters = new JobParametersBuilder() .addLong("startTime", System.currentTimeMillis()) .toJobParameters(); // 手动运行作业 JobExecution execution = jobLauncher.run(importCsvJob, jobParameters); // 验证作业执行状态 assertEquals(BatchStatus.COMPLETED, execution.getStatus()); // 验证Repository的调用符合预期 IRepository mockRepo = repositoryFactory.create("yourRepoType"); verify(mockRepo, times(expectCount)).save(any()); }
可选:轻量Mock Rest调用方案
如果不想Mock整个RepositoryFactory,用MockRestServiceServer更贴近真实流程,避免修改业务Bean的注入逻辑:
- 先修改你的
RestConfig,把用到的RestTemplate声明为Spring Bean,不要每次调用都新建实例:
@Bean public RestTemplate importRestTemplate(RestTemplateBuilder builder) { return builder.build(); // 保留你原来的配置逻辑 }
- 在业务代码中注入这个
importRestTemplate实例发起调用。 - 测试类中注入这个RestTemplate,绑定MockServer:
@Autowired private RestTemplate importRestTemplate; private MockRestServiceServer mockServer; @Before public void initMockServer() { mockServer = MockRestServiceServer.createServer(importRestTemplate); // 配置调用微服务Y的请求返回 mockServer.expect(ExpectedCount.times(3), // 预期调用次数 requestTo("http://微服务Y的请求地址")) .andExpect(method(HttpMethod.POST)) .andRespond(withStatus(HttpStatus.OK) .contentType(MediaType.APPLICATION_JSON) .body("{\"success\":true}")); }
- 作业执行完成后调用
mockServer.verify()验证所有请求都按预期发起。
内容的提问来源于stack exchange,提问作者Nick G.
相关产品推荐
相关产品推荐

