【问题标题】:SpringBoot: Configuring Spring DataSource for TestsSpring Boot:为测试配置 Spring DataSource
【发布时间】:2021-02-16 22:41:58
【问题描述】:

我有一个 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

但是当我运行测试时。我收到了这个错误:

原因: org.springframework.beans.factory.NoSuchBeanDefinitionException: 否 名为“entityManagerFactory”的 bean 可用

我也试过了:

@EnableJpaRepositories(basePackages = "com.plats.bruts.repository", entityManagerFactoryRef="emf")

然后我有错误:

原因: org.springframework.beans.factory.NoSuchBeanDefinitionException: 否 名为 'emf' 的 bean 可用

【问题讨论】:

    标签: java spring-boot spring-data-jpa spring-data h2


    【解决方案1】:

    看起来您缺少以下启动器依赖项。此启动器依赖项具有配置 jpa 存储库所需的所有必要依赖项。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    

    【讨论】:

      【解决方案2】:

      这是一种如何在一个应用程序中配置多个数据源的方法。我已经为spring-webmvcgraphql-java 测试过它,但我认为它对spring-boot 也很有用。


      spring-data-jpa配置多个数据源

      对于每个数据库,我们应该启用 JPA 存储库并指定相应接口的基本包。当然,对于每个数据库,我们应该指定实体管理器工厂和相应实体的基本包,以及事务管理器和数据源。

      为此,我们将在我们的应用程序中包含一个用于数据 JPA 的配置类和三个用于每个数据库的内部类。请参阅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;
          }
      }
      

      【讨论】:

        【解决方案3】:

        我更喜欢使用以下方法(我不喜欢创建自己的 bean 配置器)。 As @svr 正确地注意到了(请参阅上一个答案)您没有为 beans 自动配置添加启动包。 我通常创建不同的配置文件:用于本地应用程序运行,用于开发,生产,最后一个用于测试。在我的测试配置文件 (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);
            }
        }
        
        

        在我的代码示例中,我有基础测试类 - FunctionalTestBase,用于与 liquibase 交互(切换它以应用迁移)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-25
          • 2015-03-21
          • 1970-01-01
          • 2018-03-08
          • 2018-11-02
          • 2019-01-20
          相关资源
          最近更新 更多