【问题标题】:initialize database for testing purpose on Spring Data R2DBC在 Spring Data R2DBC 上初始化数据库以进行测试
【发布时间】:2021-03-28 18:32:03
【问题描述】:

在非测试环境中,我可以像这样设置 bean 以使用 schema.sql 初始化数据库

    @Bean
    ConnectionFactoryInitializer initializer(@Qualifier("connectionFactory") ConnectionFactory connectionFactory) {

        ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer();
        initializer.setConnectionFactory(connectionFactory);
        initializer.setDatabasePopulator(new ResourceDatabasePopulator(new ClassPathResource("schema.sql")));

        return initializer;
    }

问题是,我想做这样的事情,但出于测试目的。我正在尝试对数据库进行某种集成测试,因此我也希望将架构插入到虚拟数据库中。

我已经尝试过使用这个注解,但它仍然不会执行

@Sql(scripts = "classpath:schema.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)

我在我的测试资源文件夹中创建了一个单独的 application-test.properties 包含此属性值

spring.r2dbc.url=r2dbc:postgresql://localhost:5432/test
spring.r2dbc.username=postgres

logging.level.org.springframework.r2dbc=DEBUG

并且还添加了@ActiveProfiles(profiles = "test") 注释。

【问题讨论】:

    标签: java spring spring-data-r2dbc r2dbc r2dbc-postgresql


    【解决方案1】:

    我发现这是准备数据库测试环境的最简单方法

      private void initializeDatabase() {
        ConnectionFactory connectionFactory = ConnectionFactories.get(dbUrl);
        R2dbcEntityTemplate template = new R2dbcEntityTemplate(connectionFactory);
        String query = "CREATE TABLE IF NOT EXISTS member (id SERIAL PRIMARY KEY, name TEXT NOT NULL);";
        template.getDatabaseClient().sql(query).fetch().rowsUpdated().block();
      }
    

    并在 @Before 注释上调用此方法以在测试上运行

    例如,这就是我最终的结果

      @BeforeEach
      public void setup() {
        initializeDatabase();
        insertData();
      }
    
      private void initializeDatabase() {
        ConnectionFactory connectionFactory = ConnectionFactories.get(dbUrl);
        R2dbcEntityTemplate template = new R2dbcEntityTemplate(connectionFactory);
        String query = "CREATE TABLE IF NOT EXISTS member (id SERIAL PRIMARY KEY, name TEXT NOT NULL);";
        template.getDatabaseClient().sql(query).fetch().rowsUpdated().block();
      }
    
      private void insertData() {
        Flux<Member> memberFlux = Flux.just(
            Member.builder().name("Andrew").build(),
            Member.builder().name("Bob").build(),
            Member.builder().name("Charlie").build(),
            Member.builder().name("Dave").build()
        );
        memberRepository.deleteAll()
            .thenMany(memberFlux)
            .flatMap(memberRepository::save)
            .doOnNext(member -> log.info("inserted {}", member))
            .blockLast();
      }
    

    【讨论】:

    • 嗨@kamalhm,我得到这个错误,通过字段'r2dbcEntityTemplate'表示不满足的依赖关系;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException:没有“org.springframework.data.r2dbc.core.R2dbcEntityTemplate”类型的合格 bean 可用:预计至少有 1 个有资格作为自动装配候选者的 bean 你能帮我吗
    • 嗨@AleGallagher,看看这个答案-> stackoverflow.com/questions/61692151/…
    【解决方案2】:

    如果您想重用现有的src/main/resources/schema.sql,您可以通过这种方式(在 Kotlin 中)获得它:

    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    @DataR2dbcTest
    class YourRepositoryTest @Autowired constructor(
        private val yourRepository: YourRepository,
        private val r2dbcEntityTemplate: R2dbcEntityTemplate
    ) {
    
        @BeforeAll
        fun setup() {
            val schema = StreamUtils.copyToString(
                ClassPathResource("schema.sql").inputStream,
                Charset.defaultCharset()
            )
            r2dbcEntityTemplate.databaseClient.sql(schema).fetch().rowsUpdated().block()
        }
    

    此外,使用 @DataR2dbcTest 已经提供了一个 R2dbcEntityTemplate bean,因此您可以在测试中注入它。无需自己实例化它,尤其是在每次测试时。

    【讨论】:

      【解决方案3】:

      我来这里是为了寻找这个问题的答案。创建了一个 TestDBInitializer bean 加载一个 test-data.sql 文件,但即使使用 @Profile 注释它也不起作用。我发现的一个更清洁但不理想的解决方案是使用@Import({ MyTestDbInitializer.class }),如下所示:

      @DataR2dbcTest
      @Import({ TestDBInitializerConfig.class })
      class R2dbcTest {
          
          @Autowired
          private MyRepository repository;
      
          @Test
          void testSomething() {
              Flux<MyEntity> fluxResult = this.repository.findAll();
              
              StepVerifier.create(fluxResult)
                  // do things...
                  .thenConsumeWhile(x -> true)
                  .expectComplete()
                  .log()
                  .verify();
          }
      }
      
      @Configuration
      @Profile("test")
      public class MyTestDbInitializer {
      
          @Bean
          public ConnectionFactoryInitializer testProfileInitializer(ConnectionFactory connectionFactory) {
      
              ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer();
              initializer.setConnectionFactory(connectionFactory);
      
              CompositeDatabasePopulator populator = new CompositeDatabasePopulator();
              populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("schema.sql"), new ClassPathResource("test-data.sql")));
              initializer.setDatabasePopulator(populator);
      
              return initializer;
          }
      }
      

      仍在寻找不需要任何手动初始化也不需要使用@Import 注释的答案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-10
        • 1970-01-01
        • 1970-01-01
        • 2021-01-08
        • 1970-01-01
        • 2019-05-01
        • 2021-08-16
        • 2018-06-20
        相关资源
        最近更新 更多