美好的一天。我的Spring Boot应用程序使用Postgress数据库。对于测试,它使用H2数据库。在非测试模式下运行时,需要按以下顺序初始化bean:
1) Init DataSource
2) Init JPA beans
在测试模式下运行时,我需要在JPA bean初始化之前创建并填充H2数据库:
1) Init DataSource
2) Init DataSourceInitializer
3) Init JPA beans
问题是JPA bean在DataSourceInitializer之前被初始化(步骤3在步骤2之前)并且在缺失表上测试失败(hibernate.hbm2ddl.auto = validate)。
第1步
@Configuration
@EnableTransactionManagement
public class DataSourceConfig {
@Primary
@Bean
@ConfigurationProperties(prefix = "datasource.runtime")
public DataSource runtimeDataSource() {
return DataSourceBuilder.create().build();
}
}
第2步
@Configuration
@Profile(Profiles.INTEGRATION_TEST)
public class DataSourceTestConfig {
@Autowired
private ResourceLoader resourceLoader;
@Bean
public DataSourceInitializer runtimeDataSourceInitializer(@Qualifier("runtimeDataSource") DataSource dataSource) {
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource);
initializer.setDatabasePopulator(new ResourceDatabasePopulator(
resourceLoader.getResource("classpath:runtime/schema.sql")
));
return initializer;
}
}
第3步
@Configuration
@EnableTransactionManagement
public class JpaConfig {
@Autowired
private Environment environment;
@Autowired
@Qualifier(value = "runtimeDataSource")
private DataSource runtimeDataSource;
@Primary
@Bean
public LocalContainerEntityManagerFactoryBean runtimeEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(runtimeDataSource)
.properties(hibernateSettings())
.packages(
"cz.adx.anx.car.cases.domain",
"cz.adx.anx.car.lib.domain",
"org.springframework.data.jpa.convert.threeten" // Hibernate support for Java 8 date and time classes
)
.persistenceUnit("runtimePersistenceUnit")
.build();
}
}
我需要来自类DataSourceTestConfig的bean在JpaConfig之前和DataSourceConfig之后初始化,但仅在测试模式下。在非测试模式下,应该在DataSourceConfig之后初始化来自JpaConfig的bean,并且必须省略来自DataSourceTestConfig的bean。因此,我无法使用类DataSourceTestConfig中的@DependsOn bean来注释类JpaConfig,因为此类位于测试包中而不存在于非测试模式中。我可以复制配置类并使它们以配置文件为条件,但我对这个解决方案感到不舒服。拜托,有更好的解决方案吗?提前谢谢!
PS:我的应用程序使用两个数据库/数据源但我缩短了上面的代码以便于阅读。我使用的是Spring Boot 1.3.1.RELEASE。
更新1: 我尝试使用@luboskrnac建议的方法。我在我的集成测试类上放置了注释ActiveProfiles:
@ActiveProfiles("IT")
public abstract class IntegrationTest {...}
我在JpaConfig类中的相关bean上使用了注释Profile,如下所示:
@Configuration
@EnableTransactionManagement
public class JpaConfig {
@Autowired
private Environment environment;
@Autowired
@Qualifier(value = "runtimeDataSource")
private DataSource runtimeDataSource;
@Autowired
@Qualifier(value = "configDataSource")
private DataSource configDataSource;
@Profile("!IT")
@Bean(name = "runtimeEntityManagerFactory")
@DependsOn("runtimeDataSource")
public LocalContainerEntityManagerFactoryBean runtimeEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return createRuntimeEntityManagerFactory(builder);
}
@Profile("IT")
@Bean(name = "runtimeEntityManagerFactory")
@DependsOn("runtimeDataSourceInitializer")
public LocalContainerEntityManagerFactoryBean testRuntimeEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return jpaConfig.createRuntimeEntityManagerFactory(builder);
}
public LocalContainerEntityManagerFactoryBean createRuntimeEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(runtimeDataSource)
.properties(hibernateSettings())
.packages(
"cz.adx.anx.car.cases.domain",
"cz.adx.anx.car.lib.domain",
"org.springframework.data.jpa.convert.threeten" // Hibernate support for Java 8 date and time classes
)
.persistenceUnit("runtimePersistenceUnit")
.build();
}
}
我以同样的方式创建了事务管理器。因为我使用两个数据源(两个不同的数据库),所以我在EnableJpaRepositories注释中使用了bean名称。
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "runtimeEntityManagerFactory",
transactionManagerRef = "runtimeTransactionManager",
basePackages = "cz.adx.anx.car.lib.repository"
)
public class JpaCarLibRepositoryConfig {
}
所以我需要以相同名称注册的非测试bean和测试bean。但是Spring给了我一个例外:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: runtimeEntityManagerFactory
有什么建议吗?
答案 0 :(得分:1)
我建议删除有关显式bean创建排序或bean依赖项的任何注意事项。
只需根据Spring @Sql
annotation在测试中填充数据库。测试看起来像这样:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@Sql("/test-schema.sql")
public class DatabaseTests {
@Test
public void emptySchemaTest {
// execute code that uses the test schema without any test data
}
@Test
@Sql({"/test-schema.sql", "/test-user-data.sql"})
public void userTest {
// execute code that uses the test schema and test data
}
}
如果你需要交换数据源(例如在测试中使用PROD中的PostgereSQL和测试中的H2),只需使用Spring @Profile
,@ActiveProfiles
注释。