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

SpringBootTest无法自动填充Service中的Map问题求助

问题:Spring Boot测试中RepoService的Map无法自动填充

我编写了如下RepoService类,其构造函数通过收集EnumRepo和Repo类型的列表,生成对应的firstMap和secondMap:

@Service
@Slf4j
public class RepoService{
    private final Map<EnumRepoType, EnumRepo<? extends AbstractType>> firstMap;
    private final Map<RepoType, Repo<? extends AbstractType>> secondMap;

    public DictionaryService(List<EnumRepo<? extends AbstractType>> enumTypeRepositories,
                             List<Repo<? extends AbstractType>> typeRepositories) {
        this.firstMap= enumTypeRepositories.stream()
                .collect(Collectors.toMap(EnumRepo::getType, i -> i));
        this.secondMap= typeRepositories.stream()
                .collect(Collectors.toMap(Repo::getType, i -> i));
    }
}

其中EnumRepoType和RepoType均为枚举类。在应用启动时,SpringBoot能够自动填充这两个Map,但编写测试用例时却无法自动填充。我的测试代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {RepoService.class})
@ComponentScan(basePackages = {
        "package.with.repo.class"
})
public class RepoServiceTest {

    @Autowired
    RepoService repoService;

    @Test
    public void test() {
        System.out.println("whyyy map in repoService empty???");
    }
}

我发现使用@DataJpaTest注解时Map能被正确填充,使用无参数的@SpringBootTest也能正常填充,但后者会启动整个上下文,速度太慢,不符合需求。想请教这一问题的原因及高效解决办法。


原因分析

  • @SpringBootTest(classes)的限制:指定classes = {RepoService.class}后,Spring会仅初始化该类及其直接依赖的Bean,同时会覆盖默认的组件扫描逻辑。即使添加了@ComponentScan,其优先级也低于classes参数,导致EnumRepo和Repo类型的Bean未被扫描注册,无法注入构造函数生成Map。
  • @DataJpaTest的特性:该注解会自动加载JPA相关配置与Bean(包括你的Repo类),因此能正确收集列表填充Map,但仅适用于JPA相关逻辑测试,不一定适配RepoService的全部测试场景。
  • 无参数@SpringBootTest:启动完整Spring上下文,会扫描所有组件,因此Map能正常填充,但启动耗时过长。

高效解决办法

方案1:移除classes参数,精准控制组件扫描范围

去掉@SpringBootTest的classes参数,通过@ComponentScan指定RepoService与Repo类所在的包,确保仅加载必要组件:

@RunWith(SpringRunner.class)
@SpringBootTest
@ComponentScan(basePackages = {
        "package.with.repo.class",
        "package.of.repo.service" // 补充RepoService所在包
})
public class RepoServiceTest {

    @Autowired
    RepoService repoService;

    @Test
    public void test() {
        // 编写测试逻辑
    }
}

方案2:纯单元测试,手动注入依赖

无需启动Spring上下文,手动创建Repo实例并初始化RepoService,测试速度最快:

public class RepoServiceTest {

    private RepoService repoService;

    @Before
    public void setUp() {
        // 手动实例化所需的EnumRepo和Repo实现类
        List<EnumRepo<? extends AbstractType>> enumRepos = Arrays.asList(new YourEnumRepoImpl(), ...);
        List<Repo<? extends AbstractType>> repos = Arrays.asList(new YourRepoImpl(), ...);
        repoService = new RepoService(enumRepos, repos);
    }

    @Test
    public void test() {
        // 编写测试逻辑
    }
}

方案3:使用@TestConfiguration自定义测试上下文

在测试类中通过@TestConfiguration手动注册必要的Bean,既利用Spring依赖注入,又避免加载冗余组件:

@RunWith(SpringRunner.class)
@SpringBootTest
public class RepoServiceTest {

    @Autowired
    RepoService repoService;

    @TestConfiguration
    static class TestConfig {
        // 注册EnumRepo实现类
        @Bean
        public EnumRepo<? extends AbstractType> yourEnumRepo() {
            return new YourEnumRepoImpl();
        }

        // 注册Repo实现类
        @Bean
        public Repo<? extends AbstractType> yourRepo() {
            return new YourRepoImpl();
        }

        // 注册RepoService
        @Bean
        public RepoService repoService(List<EnumRepo<? extends AbstractType>> enumRepos, List<Repo<? extends AbstractType>> repos) {
            return new RepoService(enumRepos, repos);
        }
    }

    @Test
    public void test() {
        // 编写测试逻辑
    }
}

内容的提问来源于stack exchange,提问作者FaiLError

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 03:11:25