Spring @Sql 注释,可以在所有测试之前 运行 一次吗?
Spring @Sql Annotations, possible to run once before all tests?
使用 Spring 进行集成测试,我能够填充测试数据库 运行ning 脚本,就像这样...
@Test
@Sql({"/db/schema.sql", "/db/accountConfig.sql", "/db/functions/fnSomething.sql"})
public void verifySomething() {
...
}
但是,我想 运行 我的所有 .sql
文件在任何测试 运行 之前仅一次。有 JUnit 4 方法可以做到这一点吗?对于带有 @Test 注释的方法,似乎 @Sql
只有 运行s。
我正在使用 Junit 4,Spring Boot,Java 15,Testcontainers。
我尝试过的事情...
- 我已经尝试在 class 上使用
@BeforeClass
我的测试 classes extend 但在我的测试后似乎 运行。
- Testcontainers确实有一个init脚本功能,但它只需要一个文件,不太理想。
- 我也试过
ScriptUtils.executeSqlScript
但出于某种原因,测试容器不喜欢那样。
这是我的示例代码,适用于 @Sql
但不适用于 ScriptUtils.executeSqlScript
。
@ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
public abstract class AbstractIntegrationTest {
@ClassRule
public static MSSQLServerContainer mssqlserver = new MSSQLServerContainer();
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
Properties props = new Properties();
props.put("spring.datasource.driver-class-name", mssqlserver.getDriverClassName());
props.put("spring.datasource.url", mssqlserver.getJdbcUrl());
props.put("spring.datasource.username", mssqlserver.getUsername());
props.put("spring.datasource.password", mssqlserver.getPassword());
environment
.getPropertySources()
.addFirst(new PropertiesPropertySource("myTestDBProps", props));
configurableApplicationContext.setEnvironment(environment);
}
}
我的测试 class 只是扩展 AbstractIntegrationTest
。但是对每个测试用例使用 @Sql
运行s 脚本。有人对初始化 SQL 脚本的更好方法有建议吗?尝试过 flyway,但它不允许从脚本创建数据库。
您可以用 @Sql
注释您的测试 class。然后它应该在整个测试中只执行一次。然后也可以在方法级别上进行个别调整。
我建议查看在 Spring 上下文初始化时执行一次 SQL 脚本的数据库初始化程序 bean。基本上,根据您使用的是 JDBC 还是 R2DBC,有两种解决方案。既然你想初始化多个脚本,你应该使用 CompositeDatabasePopulator
。还要记住导入正确的 classes,因为它们具有相同的名称但来自不同的包,再次取决于 JDBC/R2DBC.
要从 resources
文件夹加载资源,请随意使用以下任一选项:
Resource resource = new ClassPathResource("sql/schema.sql"))
@Value("classpath:sql/schema.sql") Resource resource
这个解决方案相当灵活,因为您可以使用 @TestConfiguration
为测试上下文定义初始化程序 bean(记住使用这个注解有点棘手,所以我建议您参考这篇文章:Quirks of Spring's @TestConfiguration这对我帮助很大)。
该解决方案应该适用于任何具有 ConnectionFactory
可用的解决方案,包括 Test Containers。
JDBC
- 使用
org.springframework.jdbc.datasource.init.CompositeDatabasePopulator
- 使用
org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
通过调用 populate
进行的初始化必须在 @PostConstuct
中进行,因为 Spring 引导自动检测不到 populator。我建议将以下代码片段包装在配置 class 中并将其包含在测试范围内。
@Autowired
private DataSource dataSource;
@PostConstruct
public void initData() throws SQLException {
var populator = new CompositeDatabasePopulator();
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("sql/schema.sql")));
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("sql/catalog.sql")));
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("sql/data.sql")));
populator.populate(dataSource.getConnection());
}
R2DBC
- 使用
org.springframework.r2dbc.connection.init.CompositeDatabasePopulator
- 使用
org.springframework.r2dbc.connection.init.ResourceDatabasePopulator
您可以使用 ConnectionFactoryInitializer
在加载 Spring 上下文时初始化所有添加到此初始化程序的填充器。
@Bean
public ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) {
var populator = new CompositeDatabasePopulator();
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("sql/schema.sql")));
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("sql/catalog.sql")));
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("sql/data.sql")));
var initializer = new ConnectionFactoryInitializer();
initializer.setConnectionFactory(connectionFactory);
initializer.setDatabasePopulator(populator);
return initializer;
}
使用 Spring 进行集成测试,我能够填充测试数据库 运行ning 脚本,就像这样...
@Test
@Sql({"/db/schema.sql", "/db/accountConfig.sql", "/db/functions/fnSomething.sql"})
public void verifySomething() {
...
}
但是,我想 运行 我的所有 .sql
文件在任何测试 运行 之前仅一次。有 JUnit 4 方法可以做到这一点吗?对于带有 @Test 注释的方法,似乎 @Sql
只有 运行s。
我正在使用 Junit 4,Spring Boot,Java 15,Testcontainers。
我尝试过的事情...
- 我已经尝试在 class 上使用
@BeforeClass
我的测试 classes extend 但在我的测试后似乎 运行。 - Testcontainers确实有一个init脚本功能,但它只需要一个文件,不太理想。
- 我也试过
ScriptUtils.executeSqlScript
但出于某种原因,测试容器不喜欢那样。
这是我的示例代码,适用于 @Sql
但不适用于 ScriptUtils.executeSqlScript
。
@ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
public abstract class AbstractIntegrationTest {
@ClassRule
public static MSSQLServerContainer mssqlserver = new MSSQLServerContainer();
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
Properties props = new Properties();
props.put("spring.datasource.driver-class-name", mssqlserver.getDriverClassName());
props.put("spring.datasource.url", mssqlserver.getJdbcUrl());
props.put("spring.datasource.username", mssqlserver.getUsername());
props.put("spring.datasource.password", mssqlserver.getPassword());
environment
.getPropertySources()
.addFirst(new PropertiesPropertySource("myTestDBProps", props));
configurableApplicationContext.setEnvironment(environment);
}
}
我的测试 class 只是扩展 AbstractIntegrationTest
。但是对每个测试用例使用 @Sql
运行s 脚本。有人对初始化 SQL 脚本的更好方法有建议吗?尝试过 flyway,但它不允许从脚本创建数据库。
您可以用 @Sql
注释您的测试 class。然后它应该在整个测试中只执行一次。然后也可以在方法级别上进行个别调整。
我建议查看在 Spring 上下文初始化时执行一次 SQL 脚本的数据库初始化程序 bean。基本上,根据您使用的是 JDBC 还是 R2DBC,有两种解决方案。既然你想初始化多个脚本,你应该使用 CompositeDatabasePopulator
。还要记住导入正确的 classes,因为它们具有相同的名称但来自不同的包,再次取决于 JDBC/R2DBC.
要从 resources
文件夹加载资源,请随意使用以下任一选项:
Resource resource = new ClassPathResource("sql/schema.sql"))
@Value("classpath:sql/schema.sql") Resource resource
这个解决方案相当灵活,因为您可以使用 @TestConfiguration
为测试上下文定义初始化程序 bean(记住使用这个注解有点棘手,所以我建议您参考这篇文章:Quirks of Spring's @TestConfiguration这对我帮助很大)。
该解决方案应该适用于任何具有 ConnectionFactory
可用的解决方案,包括 Test Containers。
JDBC
- 使用
org.springframework.jdbc.datasource.init.CompositeDatabasePopulator
- 使用
org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
通过调用 populate
进行的初始化必须在 @PostConstuct
中进行,因为 Spring 引导自动检测不到 populator。我建议将以下代码片段包装在配置 class 中并将其包含在测试范围内。
@Autowired
private DataSource dataSource;
@PostConstruct
public void initData() throws SQLException {
var populator = new CompositeDatabasePopulator();
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("sql/schema.sql")));
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("sql/catalog.sql")));
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("sql/data.sql")));
populator.populate(dataSource.getConnection());
}
R2DBC
- 使用
org.springframework.r2dbc.connection.init.CompositeDatabasePopulator
- 使用
org.springframework.r2dbc.connection.init.ResourceDatabasePopulator
您可以使用 ConnectionFactoryInitializer
在加载 Spring 上下文时初始化所有添加到此初始化程序的填充器。
@Bean
public ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) {
var populator = new CompositeDatabasePopulator();
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("sql/schema.sql")));
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("sql/catalog.sql")));
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("sql/data.sql")));
var initializer = new ConnectionFactoryInitializer();
initializer.setConnectionFactory(connectionFactory);
initializer.setDatabasePopulator(populator);
return initializer;
}