1

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

    @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")注释。

4

3 回答 3

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();
  }
于 2021-01-09T16:23:46.657 回答
1

如果您想重用现有的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()
    }

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

于 2021-03-09T04:05:09.363 回答
0

我来这里是为了寻找这个问题的答案。创建了一个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注释的答案。

于 2021-06-25T00:26:33.567 回答