You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot集成测试:如何在应用上下文启动前Mock @Service服务

解决方案

问题根因

  • Mock不生效核心是两个初始化时机冲突:
    1. Spring Boot定时任务在应用上下文初始化完成后立刻执行,此时测试类的Mock/桩方法还没完成配置,作业运行时调用的是原始对象
    2. 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的注入逻辑:

  1. 先修改你的RestConfig,把用到的RestTemplate声明为Spring Bean,不要每次调用都新建实例:
@Bean
public RestTemplate importRestTemplate(RestTemplateBuilder builder) {
    return builder.build(); // 保留你原来的配置逻辑
}
  1. 在业务代码中注入这个importRestTemplate实例发起调用。
  2. 测试类中注入这个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}"));
}
  1. 作业执行完成后调用mockServer.verify()验证所有请求都按预期发起。

内容的提问来源于stack exchange,提问作者Nick G.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 09:21:02