Spring启动:为测试配置 Spring 数据源
SpringBoot: Configuring Spring DataSource for Tests
我有一个 SpringBoot 应用程序。
我创建了这个测试:
@ContextConfiguration(classes={TestConfig.class})
@RunWith(SpringRunner.class)
@SpringBootTest
public class SuncionServiceITTest {
@Test
public void should_Find_2() {
// TODO
}
}
哪里
@Configuration
@EnableJpaRepositories(basePackages = "com.plats.bruts.repository")
@PropertySource("local-configuration.properties")
@EnableTransactionManagement
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class TestConfig {
}
和本地 configuration.properties
:
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
但是当我运行考试的时候。我收到此错误:
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named 'entityManagerFactory' available
我也试过:
@EnableJpaRepositories(basePackages = "com.plats.bruts.repository", entityManagerFactoryRef="emf")
但是我遇到了错误:
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named 'emf' available
这是一种在一个应用程序中配置多个数据源的方法。我已经对 spring-webmvc
和 graphql-java
进行了测试,但我认为它对 spring-boot
也很有用。
配置多个数据源spring-data-jpa
对于每个数据库,我们应该启用 JPA 存储库并为相应的接口指定基础包。此外,对于每个数据库,我们应该指定实体管理器工厂和相应实体的基础包,当然还有事务管理器和数据源。
为此,我们将在我们的应用程序中包含一个配置 class 用于数据 JPA 和三个内部 class es 用于每个数据库。见 Simple GraphQL implementation.
DataJpaConfig.java
package org.drakonoved.graphql;
@Configuration
@PropertySource(value = "classpath:resources/application.properties", encoding = "UTF-8")
public class DataJpaConfig {
private final String basePackage = "org.drakonoved.graphql";
@EnableJpaRepositories(
basePackages = basePackage + ".repository.usersdb",
entityManagerFactoryRef = "usersdbEntityManagerFactory",
transactionManagerRef = "usersdbTransactionManager")
public class UsersDBJpaConfig {
@Bean("usersdbEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean usersDBEntityManagerFactoryBean(
@Value("${datasource.usersdb.script}") String script) {
return createEntityManagerFactoryBean(
script, "usersdb", basePackage + ".dto.usersdb");
}
@Bean("usersdbTransactionManager")
public PlatformTransactionManager usersDBTransactionManager(
@Qualifier("usersdbEntityManagerFactory")
LocalContainerEntityManagerFactoryBean factoryBean) {
return new JpaTransactionManager(factoryBean.getNativeEntityManagerFactory());
}
}
@EnableJpaRepositories(
basePackages = basePackage + ".repository.rolesdb",
entityManagerFactoryRef = "rolesdbEntityManagerFactory",
transactionManagerRef = "rolesdbTransactionManager")
public class RolesDBJpaConfig {
@Bean("rolesdbEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean rolesDBEntityManagerFactoryBean(
@Value("${datasource.rolesdb.script}") String script) {
return createEntityManagerFactoryBean(
script, "rolesdb", basePackage + ".dto.rolesdb");
}
@Bean("rolesdbTransactionManager")
public PlatformTransactionManager rolesDBTransactionManager(
@Qualifier("rolesdbEntityManagerFactory")
LocalContainerEntityManagerFactoryBean factoryBean) {
return new JpaTransactionManager(factoryBean.getNativeEntityManagerFactory());
}
}
@EnableJpaRepositories(
basePackages = basePackage + ".repository.usersnrolesdb",
entityManagerFactoryRef = "usersnrolesdbEntityManagerFactory",
transactionManagerRef = "usersnrolesdbTransactionManager")
public class UsersNRolesDBJpaConfig {
@Bean("usersnrolesdbEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean usersNRolesDBEntityManagerFactoryBean(
@Value("${datasource.usersnrolesdb.script}") String script) {
return createEntityManagerFactoryBean(
script, "usersnrolesdb", basePackage + ".dto.usersnrolesdb");
}
@Bean("usersnrolesdbTransactionManager")
public PlatformTransactionManager usersNRolesDBTransactionManager(
@Qualifier("usersnrolesdbEntityManagerFactory")
LocalContainerEntityManagerFactoryBean factoryBean) {
return new JpaTransactionManager(factoryBean.getNativeEntityManagerFactory());
}
}
//////// //////// //////// //////// //////// //////// //////// ////////
private LocalContainerEntityManagerFactoryBean createEntityManagerFactoryBean(
String script, String dbname, String packagesToScan) {
var factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setName(dbname)
.addScript(script)
.build());
factoryBean.setPersistenceUnitName(dbname + "EntityManagerFactory");
factoryBean.setPackagesToScan(packagesToScan);
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
var properties = new HashMap<String, Object>();
properties.put("hibernate.hbm2ddl.auto", "none");
properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
factoryBean.setJpaPropertyMap(properties);
return factoryBean;
}
}
看起来你缺少启动器依赖项。此入门依赖项具有配置 jpa
存储库所需的所有必要依赖项。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
我更喜欢使用以下方法(我不喜欢创建自己的 bean 配置器)。 As @svr 正确地注意到(参见前面的回答)您没有为 bean 自动配置添加启动包。
我通常创建不同的配置文件:用于本地应用程序 运行、用于开发、生产,最后一个用于测试。在我的测试配置文件 (application-functests.yml) 中,我配置了我的功能测试所需的所有设置(数据源、休眠、缓存等),即我的一个项目的 application-functests.yml:
spring:
http:
encoding:
charset: UTF-8
enabled: true
profiles: functests
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
enable_lazy_load_no_trans: true
naming:
physical-strategy: com.goodt.drive.orgstructure.application.utils.SnakePhysicalNamingStrategy
hibernate:
ddl-auto: none
database-platform: org.hibernate.dialect.PostgreSQL9Dialect
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/monitor_service_functests
username: developer
password: 123
sql-script-encoding: UTF-8
liquibase:
change-log: classpath:db/changelog/changelog.xml
我只为 运行 测试指定了配置文件,因此我所有的功能测试都使用 functests 配置文件,即:
@SpringBootTest
@ActiveProfiles("functests")
public class TestEventRepository extends FunctionalTestBase {
@Test
public void testGetAll() {
Iterable<EventEntity> eventIterable = dbContext.getEventDataSource().findAll();
Iterator<EventEntity> it = eventIterable.iterator();
List<EventEntity> actualEvents = new ArrayList<>();
while (it.hasNext()) {
actualEvents.add(it.next());
}
List<EventCheckData> expectedEvents = new ArrayList<>() {{
add(new EventCheckData(1L, 1L, "body 1", 1L, 1L));
add(new EventCheckData(2L, 2L, "body 2", 2L, 2L));
add(new EventCheckData(3L, 3L, "body 3", 3L, 1L));
add(new EventCheckData(4L, 1L, "body 4", 2L, 1L));
add(new EventCheckData(5L, 2L, "body 5", 1L, 2L));
}};
EventSimpleChecker.check(expectedEvents, actualEvents);
}
}
在我的代码示例中,我有基础测试 class - FunctionalTestBase 用于与 liquibase 交互(切换它以应用迁移)
我有一个 SpringBoot 应用程序。
我创建了这个测试:
@ContextConfiguration(classes={TestConfig.class})
@RunWith(SpringRunner.class)
@SpringBootTest
public class SuncionServiceITTest {
@Test
public void should_Find_2() {
// TODO
}
}
哪里
@Configuration
@EnableJpaRepositories(basePackages = "com.plats.bruts.repository")
@PropertySource("local-configuration.properties")
@EnableTransactionManagement
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class TestConfig {
}
和本地 configuration.properties
:
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
但是当我运行考试的时候。我收到此错误:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
我也试过:
@EnableJpaRepositories(basePackages = "com.plats.bruts.repository", entityManagerFactoryRef="emf")
但是我遇到了错误:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'emf' available
这是一种在一个应用程序中配置多个数据源的方法。我已经对 spring-webmvc
和 graphql-java
进行了测试,但我认为它对 spring-boot
也很有用。
配置多个数据源spring-data-jpa
对于每个数据库,我们应该启用 JPA 存储库并为相应的接口指定基础包。此外,对于每个数据库,我们应该指定实体管理器工厂和相应实体的基础包,当然还有事务管理器和数据源。
为此,我们将在我们的应用程序中包含一个配置 class 用于数据 JPA 和三个内部 class es 用于每个数据库。见 Simple GraphQL implementation.
DataJpaConfig.java
package org.drakonoved.graphql;
@Configuration
@PropertySource(value = "classpath:resources/application.properties", encoding = "UTF-8")
public class DataJpaConfig {
private final String basePackage = "org.drakonoved.graphql";
@EnableJpaRepositories(
basePackages = basePackage + ".repository.usersdb",
entityManagerFactoryRef = "usersdbEntityManagerFactory",
transactionManagerRef = "usersdbTransactionManager")
public class UsersDBJpaConfig {
@Bean("usersdbEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean usersDBEntityManagerFactoryBean(
@Value("${datasource.usersdb.script}") String script) {
return createEntityManagerFactoryBean(
script, "usersdb", basePackage + ".dto.usersdb");
}
@Bean("usersdbTransactionManager")
public PlatformTransactionManager usersDBTransactionManager(
@Qualifier("usersdbEntityManagerFactory")
LocalContainerEntityManagerFactoryBean factoryBean) {
return new JpaTransactionManager(factoryBean.getNativeEntityManagerFactory());
}
}
@EnableJpaRepositories(
basePackages = basePackage + ".repository.rolesdb",
entityManagerFactoryRef = "rolesdbEntityManagerFactory",
transactionManagerRef = "rolesdbTransactionManager")
public class RolesDBJpaConfig {
@Bean("rolesdbEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean rolesDBEntityManagerFactoryBean(
@Value("${datasource.rolesdb.script}") String script) {
return createEntityManagerFactoryBean(
script, "rolesdb", basePackage + ".dto.rolesdb");
}
@Bean("rolesdbTransactionManager")
public PlatformTransactionManager rolesDBTransactionManager(
@Qualifier("rolesdbEntityManagerFactory")
LocalContainerEntityManagerFactoryBean factoryBean) {
return new JpaTransactionManager(factoryBean.getNativeEntityManagerFactory());
}
}
@EnableJpaRepositories(
basePackages = basePackage + ".repository.usersnrolesdb",
entityManagerFactoryRef = "usersnrolesdbEntityManagerFactory",
transactionManagerRef = "usersnrolesdbTransactionManager")
public class UsersNRolesDBJpaConfig {
@Bean("usersnrolesdbEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean usersNRolesDBEntityManagerFactoryBean(
@Value("${datasource.usersnrolesdb.script}") String script) {
return createEntityManagerFactoryBean(
script, "usersnrolesdb", basePackage + ".dto.usersnrolesdb");
}
@Bean("usersnrolesdbTransactionManager")
public PlatformTransactionManager usersNRolesDBTransactionManager(
@Qualifier("usersnrolesdbEntityManagerFactory")
LocalContainerEntityManagerFactoryBean factoryBean) {
return new JpaTransactionManager(factoryBean.getNativeEntityManagerFactory());
}
}
//////// //////// //////// //////// //////// //////// //////// ////////
private LocalContainerEntityManagerFactoryBean createEntityManagerFactoryBean(
String script, String dbname, String packagesToScan) {
var factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setName(dbname)
.addScript(script)
.build());
factoryBean.setPersistenceUnitName(dbname + "EntityManagerFactory");
factoryBean.setPackagesToScan(packagesToScan);
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
var properties = new HashMap<String, Object>();
properties.put("hibernate.hbm2ddl.auto", "none");
properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
factoryBean.setJpaPropertyMap(properties);
return factoryBean;
}
}
看起来你缺少启动器依赖项。此入门依赖项具有配置 jpa
存储库所需的所有必要依赖项。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
我更喜欢使用以下方法(我不喜欢创建自己的 bean 配置器)。 As @svr 正确地注意到(参见前面的回答)您没有为 bean 自动配置添加启动包。 我通常创建不同的配置文件:用于本地应用程序 运行、用于开发、生产,最后一个用于测试。在我的测试配置文件 (application-functests.yml) 中,我配置了我的功能测试所需的所有设置(数据源、休眠、缓存等),即我的一个项目的 application-functests.yml:
spring:
http:
encoding:
charset: UTF-8
enabled: true
profiles: functests
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
enable_lazy_load_no_trans: true
naming:
physical-strategy: com.goodt.drive.orgstructure.application.utils.SnakePhysicalNamingStrategy
hibernate:
ddl-auto: none
database-platform: org.hibernate.dialect.PostgreSQL9Dialect
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/monitor_service_functests
username: developer
password: 123
sql-script-encoding: UTF-8
liquibase:
change-log: classpath:db/changelog/changelog.xml
我只为 运行 测试指定了配置文件,因此我所有的功能测试都使用 functests 配置文件,即:
@SpringBootTest
@ActiveProfiles("functests")
public class TestEventRepository extends FunctionalTestBase {
@Test
public void testGetAll() {
Iterable<EventEntity> eventIterable = dbContext.getEventDataSource().findAll();
Iterator<EventEntity> it = eventIterable.iterator();
List<EventEntity> actualEvents = new ArrayList<>();
while (it.hasNext()) {
actualEvents.add(it.next());
}
List<EventCheckData> expectedEvents = new ArrayList<>() {{
add(new EventCheckData(1L, 1L, "body 1", 1L, 1L));
add(new EventCheckData(2L, 2L, "body 2", 2L, 2L));
add(new EventCheckData(3L, 3L, "body 3", 3L, 1L));
add(new EventCheckData(4L, 1L, "body 4", 2L, 1L));
add(new EventCheckData(5L, 2L, "body 5", 1L, 2L));
}};
EventSimpleChecker.check(expectedEvents, actualEvents);
}
}
在我的代码示例中,我有基础测试 class - FunctionalTestBase 用于与 liquibase 交互(切换它以应用迁移)