向Spring Boot项目添加依赖与ComponentScan后JUnit测试失效
嘿,我之前也碰到过几乎一模一样的坑!咱们先搞清楚为啥会出这问题,再一步步解决:
问题到底出在哪?
你给项目2加了@ComponentScan(basePackages="com.project1")之后,Spring Boot会把项目1包里的所有东西都扫进项目2的上下文——包括项目1里的数据源配置类、数据库Repository这些。如果项目1本身是个完整的Spring Boot应用,它肯定有自己的数据源配置,但项目2里没配对应的数据库连接参数呀!这时候Spring尝试初始化项目1带过来的数据源相关Bean,自然就会喊“dataSource没设置”了。而且@SpringBootTest默认会加载完整的应用上下文,这就把冲突彻底暴露出来了。
具体怎么解决?
1. 别贪多,只扫你需要的服务
别直接扫整个com.project1包,精准定位到你要调用的服务所在的子包或者具体类就行,这样就不会把项目1的配置、Repository这些无关的东西带进来。比如:
// 只扫项目1的service层 @ComponentScan(basePackages = "com.project1.service") // 或者更精准,直接指定你要用的那个服务类 @ComponentScan(basePackageClasses = {你要调用的项目1服务类.class})
2. 把捣乱的配置类排除掉
如果必须扫项目1的整个包,那就在扫描的时候把那些数据源相关的配置类排除出去。比如你知道项目1里有个Project1DataSourceConfig的配置类,就这么写:
@ComponentScan( basePackages = "com.project1", excludeFilters = @ComponentScan.Filter( type = FilterType.ASSIGNABLE_TYPE, classes = {Project1DataSourceConfig.class} ) )
要是不知道具体是哪个配置类,也可以按注解排除所有@Configuration类(不过这个要谨慎,别把你需要的配置也排除了):
@ComponentScan( basePackages = "com.project1", excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class) )
3. 给JUnit测试“瘦身”,只加载必要的上下文
如果你的测试只是验证项目2自己的逻辑,根本不需要项目1的组件,那就在测试类里指定只加载项目2的主启动类:
@SpringBootTest(classes = 项目2的主启动类.class) @RunWith(SpringRunner.class) public class Project2Test { // 你的测试代码 }
要是测试确实需要调用项目1的服务,那就单独写个测试配置类,只导入你需要的那个服务:
@Configuration @Import(你要调用的项目1服务类.class) public class TestConfig { } // 然后测试类这么写 @SpringBootTest(classes = {项目2的主启动类.class, TestConfig.class}) @RunWith(SpringRunner.class) public class Project2WithProject1ServiceTest { @Autowired private 你要调用的项目1服务类 project1Service; // 测试调用逻辑 }
4. 从根源上避免冲突:拆分项目结构
其实最规范的做法是把项目1里需要对外提供的服务抽成一个独立的公共模块——比如叫project1-api,里面只放服务接口和DTO;然后项目1的业务实现依赖这个api模块,项目2也只依赖这个api模块,再引入项目1的实现Jar(注意排除掉不必要的自动配置)。这样就不会把项目1的整个应用配置都带进项目2了,从根源上解决冲突。
内容的提问来源于stack exchange,提问作者Tristan

