如何在不重复JPA配置类的前提下将H2依赖设为test scope?
问题分析
运行mvn clean verify -Denv=dev测试时出现Could not load JDBC driver class [org.h2.Driver]错误,核心原因:
- 测试阶段会加载主类路径下的
PersistenceJpaConfig,该配置读取persistence-dev.properties中的H2驱动配置; - 但H2依赖被设置为
testscope,主类路径(compile scope)不包含该依赖,导致Spring创建DataSource Bean时无法找到H2驱动类。
解决方案
方案一:用Spring Profiles隔离主环境与测试环境配置
1. 修改主配置类的生效范围
给PersistenceJpaConfig添加@Profile注解,限制它仅在非测试环境生效:
@Configuration @EnableTransactionManagement @PropertySource("classpath:persistence-${env:int}.properties") @EnableJpaRepositories(basePackages = "fr.tristan.demoassurance.infrastructure.repository.mysql") @Profile("!test") // 仅在非test Profile下激活 @SuppressWarnings("unused") public class PersistenceJpaConfig { // 原有代码保持不变 }
2. 创建测试专用JPA配置类
在测试类路径(src/test/java)下新建测试配置类,仅在test Profile生效:
@Configuration @EnableTransactionManagement @PropertySource("classpath:persistence-test.properties") @EnableJpaRepositories(basePackages = "fr.tristan.demoassurance.infrastructure.repository.mysql") @Profile("test") public class TestPersistenceJpaConfig { @Bean LocalContainerEntityManagerFactoryBean entityManagerFactory(Environment env) { final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource(dataSource(env)); em.setPackagesToScan("fr.tristan.demoassurance.infrastructure.repository.mysql.entity"); final JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); em.setJpaVendorAdapter(vendorAdapter); em.setJpaProperties(additionalProperties(env)); return em; } @Bean DataSource dataSource(Environment env) { final DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName"))); dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url"))); dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user"))); dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass"))); return dataSource; } @Bean PlatformTransactionManager transactionManager(EntityManagerFactory emf) { final JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(emf); return transactionManager; } @Bean PersistenceExceptionTranslationPostProcessor exceptionTranslation() { return new PersistenceExceptionTranslationPostProcessor(); } final Properties additionalProperties(Environment env) { final Properties hibernateProperties = new Properties(); hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); hibernateProperties.setProperty("hibernate.hbm2ddl.import_files", env.getProperty("hibernate.hbm2ddl.import_files")); hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect")); hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", env.getProperty("hibernate.cache.use_second_level_cache")); hibernateProperties.setProperty("hibernate.cache.use_query_cache", env.getProperty("hibernate.cache.use_query_cache")); return hibernateProperties; } }
3. 激活测试类的test Profile
@SpringBootTest @ActiveProfiles("test") public class DemoAssuranceServiceIntegrationTest { // 测试代码 }
4. 新增测试配置文件
在测试资源路径(src/test/resources)下创建persistence-test.properties:
jdbc.driverClassName=org.h2.Driver jdbc.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 jdbc.user=sa jdbc.pass= hibernate.hbm2ddl.auto=create-drop hibernate.hbm2ddl.import_files=import-test-data.sql hibernate.dialect=org.hibernate.dialect.H2Dialect hibernate.cache.use_second_level_cache=false hibernate.cache.use_query_cache=false
方案二:在主配置类中动态适配测试环境
无需新增测试配置类,修改主配置类的dataSource方法,根据当前Profile动态切换数据源配置:
@Bean DataSource dataSource(Environment env) { final DriverManagerDataSource dataSource = new DriverManagerDataSource(); // 判断是否为测试环境 if (env.acceptsProfiles(Profiles.of("test"))) { // 测试环境直接使用H2嵌入式数据库配置 dataSource.setDriverClassName("org.h2.Driver"); dataSource.setUrl("jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1"); dataSource.setUsername("sa"); dataSource.setPassword(""); } else { // 非测试环境读取配置文件中的参数 dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName"))); dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url"))); dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user"))); dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass"))); } return dataSource; }
同时在测试类上添加@ActiveProfiles("test"),测试时自动切换到H2配置。
内容的提问来源于stack exchange,提问作者Tristan
相关产品推荐
相关产品推荐

