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
相关产品推荐
相关产品推荐

