为 Spring 数据 R2DBC 上的测试目的初始化数据库
initialize database for testing purpose on Spring Data R2DBC
在非测试环境中,我可以像这样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")
注释。
我发现这是准备数据库测试环境的最简单方法
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();
}
如果您想重用现有的 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,因此您可以将其注入到您的测试中。无需自己实例化,尤其是在每次测试时。
我来这里是为了寻找这个问题的答案。创建了一个 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
注释的答案。
在非测试环境中,我可以像这样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")
注释。
我发现这是准备数据库测试环境的最简单方法
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();
}
如果您想重用现有的 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,因此您可以将其注入到您的测试中。无需自己实例化,尤其是在每次测试时。
我来这里是为了寻找这个问题的答案。创建了一个 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
注释的答案。