Spring boot 在SpringBoot集成测试中使用TestContainers填充数据库
我正在测试TestContainers,我想知道如何通过执行.sql文件来填充数据库,以创建结构并添加一些行 怎么做Spring boot 在SpringBoot集成测试中使用TestContainers填充数据库,spring-boot,testcontainers,Spring Boot,Testcontainers,我正在测试TestContainers,我想知道如何通过执行.sql文件来填充数据库,以创建结构并添加一些行 怎么做 @Rule public PostgreSQLContainer postgres = new PostgreSQLContainer(); 使用SpringBoot时,我发现使用TestContainers的JDBCURL支持最简单 您可以创建一个应用程序集成test.properties文件(通常位于src/test/resources中),如下所示: spring.dat
@Rule
public PostgreSQLContainer postgres = new PostgreSQLContainer();
使用SpringBoot时,我发现使用TestContainers的JDBCURL支持最简单 您可以创建一个
应用程序集成test.properties
文件(通常位于src/test/resources
中),如下所示:
spring.datasource.url=jdbc:tc:postgresql://localhost/myappdb
spring.datasource.driverClassName=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.datasource.username=user
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=none
# This line is only needed if you are using flyway for database migrations
# and not using the default location of `db/migration`
spring.flyway.locations=classpath:db/migration/postgresql
@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ActiveProfiles("integration-test")
public class UserRepositoryIntegrationTest {
@Autowired
private MyObjectRepository repository;
@PersistenceContext
private EntityManager entityManager;
@Autowired
private JdbcTemplate template;
@Test
public void test() {
// use your Spring Data repository, or the EntityManager or the JdbcTemplate to run your SQL and populate your database.
}
注意JDBC url中的:tc
部分
现在可以编写如下的单元测试:
spring.datasource.url=jdbc:tc:postgresql://localhost/myappdb
spring.datasource.driverClassName=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.datasource.username=user
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=none
# This line is only needed if you are using flyway for database migrations
# and not using the default location of `db/migration`
spring.flyway.locations=classpath:db/migration/postgresql
@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ActiveProfiles("integration-test")
public class UserRepositoryIntegrationTest {
@Autowired
private MyObjectRepository repository;
@PersistenceContext
private EntityManager entityManager;
@Autowired
private JdbcTemplate template;
@Test
public void test() {
// use your Spring Data repository, or the EntityManager or the JdbcTemplate to run your SQL and populate your database.
}
注意:第7章对此进行了更详细的解释(免责声明:我是本书的作者)Spring framework提供了为测试套件或测试单元执行SQL脚本的能力。例如:
@Test
@Sql({"/test-schema.sql", "/test-user-data.sql"})
public void userTest {
// execute code that relies on the test schema and test data
}
这是我的建议
您还可以查看为测试单元填充数据库所提供的注释。它使用XML数据集文件
@Test
@DatabaseSetup(value = "insert.xml")
@DatabaseTearDown(value = "insert.xml")
public void testInsert() throws Exception {
// Inserts "insert.xml" before test execution
// Remove "insert.xml" after test execution
}
另外,您还可以查看,它提供了一个java fluent DSL来填充您的数据库。您可以使用,它在后台用于填充测试数据库并作为测试数据源。下面是一个示例测试,上提供了完整的源代码
src/test/resources/application integration test.properties
spring.datasource.url=jdbc:tc:postgresql://localhost/test
spring.datasource.driverClassName=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.datasource.username=test
spring.datasource.password=test
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
#spring.jpa.properties.org.hibernate.flushMode=ALWAYS #doesn't take effect
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
最后是数据集:
src/test/resources/dataset/users.yml
users:
- ID: 1
EMAIL: "dbunit@gmail.com"
NAME: "dbunit"
- ID: 2
EMAIL: "rmpestano@gmail.com"
NAME: "rmpestano"
- ID: 3
EMAIL: "springboot@gmail.com"
NAME: "springboot"
users:
- ID: 1
EMAIL: "dbunit@gmail.com"
NAME: "dbunit"
- ID: 3
EMAIL: "springboot@gmail.com"
NAME: "springboot"
users:
- ID: "regex:\\d+"
EMAIL: "newUser@gmail.com"
NAME: "new user"
src/test/resources/dataset/expected_users.yml
users:
- ID: 1
EMAIL: "dbunit@gmail.com"
NAME: "dbunit"
- ID: 2
EMAIL: "rmpestano@gmail.com"
NAME: "rmpestano"
- ID: 3
EMAIL: "springboot@gmail.com"
NAME: "springboot"
users:
- ID: 1
EMAIL: "dbunit@gmail.com"
NAME: "dbunit"
- ID: 3
EMAIL: "springboot@gmail.com"
NAME: "springboot"
users:
- ID: "regex:\\d+"
EMAIL: "newUser@gmail.com"
NAME: "new user"
src/test/resources/dataset/user.yml
users:
- ID: 1
EMAIL: "dbunit@gmail.com"
NAME: "dbunit"
- ID: 2
EMAIL: "rmpestano@gmail.com"
NAME: "rmpestano"
- ID: 3
EMAIL: "springboot@gmail.com"
NAME: "springboot"
users:
- ID: 1
EMAIL: "dbunit@gmail.com"
NAME: "dbunit"
- ID: 3
EMAIL: "springboot@gmail.com"
NAME: "springboot"
users:
- ID: "regex:\\d+"
EMAIL: "newUser@gmail.com"
NAME: "new user"
在进行了一些回顾之后,我认为回顾Spring Data JDBC中使用测试容器的示例很有趣: 注意:使用Java 8
git clone https://github.com/spring-projects/spring-data-jdbc.git
mvn clean install -Pall-dbs
我将创建一个简单的项目,添加一些关于以前引用的项目的想法
Juan Antonio如果您手动定义Postgres容器,而不使用高级testcontainers JDBC url,那么还有一个选项,它与Spring没有直接关系。Postgres映像允许将包含sql脚本的目录链接到容器卷并自动执行它们
GenericContainer pgDb = new PostgreSQLContainer("postgres:9.4-alpine")
.withFileSystemBind("migrations/sqls", "/docker-entrypoint-initdb.d",
BindMode.READ_ONLY)
如果您在运行时需要一些东西,您也可以随时这样做
pgDb.execInContainer(“psql….”)
最简单的方法是使用JdbcDatabaseContainer::withInitScript
此解决方案的优点是,脚本在加载Spring应用程序上下文之前运行(至少在静态块中时),代码非常简单
例如:
static {
postgreSQLContainer = new PostgreSQLContainer("postgres:9.6.8")
.withDatabaseName("integration-tests-db")
.withUsername("sa")
.withPassword("sa");
postgreSQLContainer
.withInitScript("some/location/on/classpath/someScript.sql");
postgreSQLContainer.start();
}
static {
postgreSQLContainer = new PostgreSQLContainer("postgres:9.6.8")
.withDatabaseName("integration-tests-db")
.withUsername("sa")
.withPassword("sa");
postgreSQLContainer.start();
var containerDelegate = new JdbcDatabaseDelegate(postgreSQLContainer, "");
ScriptUtils.runInitScript(containerDelegate, "some/location/on/classpath/someScriptFirst.sql");
ScriptUtils.runInitScript(containerDelegate, "some/location/on/classpath/someScriptSecond.sql");
ScriptUtils.runInitScript(containerDelegate, "ssome/location/on/classpath/someScriptThird.sql");
}
JdbcDatabaseContainer
是postgresqlcainer
的超类,因此此解决方案不仅适用于postgres
,也适用于其他容器
如果你想运行多个脚本,你可以用类似的方式
例如:
static {
postgreSQLContainer = new PostgreSQLContainer("postgres:9.6.8")
.withDatabaseName("integration-tests-db")
.withUsername("sa")
.withPassword("sa");
postgreSQLContainer
.withInitScript("some/location/on/classpath/someScript.sql");
postgreSQLContainer.start();
}
static {
postgreSQLContainer = new PostgreSQLContainer("postgres:9.6.8")
.withDatabaseName("integration-tests-db")
.withUsername("sa")
.withPassword("sa");
postgreSQLContainer.start();
var containerDelegate = new JdbcDatabaseDelegate(postgreSQLContainer, "");
ScriptUtils.runInitScript(containerDelegate, "some/location/on/classpath/someScriptFirst.sql");
ScriptUtils.runInitScript(containerDelegate, "some/location/on/classpath/someScriptSecond.sql");
ScriptUtils.runInitScript(containerDelegate, "ssome/location/on/classpath/someScriptThird.sql");
}
还有其他选择
弹簧测试@Sql
注释
ResourceDatabasePopulator
fromjdbc.datasource.init
或r2dbc.connection.init
连续使用jdbc
或r2dbc
时
使用JDBC时数据库URI中的Init脚本
它在官方Testcontainers
文档中提到:
类路径文件:
jdbc:tc:postgresql:9.6.8:///databasename?tc_INITSCRIPT=somepath/init_mysql.sql
不在类路径上但其路径相对于工作目录的文件,工作目录通常是项目根目录:
jdbc:tc:postgresql:9.6.8:///databasename?tc_INITSCRIPT=file:src/main/resources/init_mysql.sql
使用初始化函数:
jdbc:tc:postgresql:9.6.8:///databasename?tc_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction
package org.testcontainers.jdbc;
public class JDBCDriverTest {
public static void sampleInitFunction(Connection connection) throws SQLException {
// e.g. run schema setup or Flyway/liquibase/etc DB migrations here...
}
...
}
您是否只使用JUnit和TestContainers?或者也使用其他框架,例如Spring Boot?您好,我在Spring Boot环境中使用此库您可以在文档中找到:还有一篇文章提到了PostgreSQLContainer::withInitScript
方法的用法:实际上它是JdbcDatabaseContainer::withInitScript
其中JdbcDatabaseContainer
是postgresqlcainer
的超类,因此它不仅适用于postgres,也适用于其他容器。您好,Wim,感谢您的回复。有趣的答案是,对于TestContainers,不需要重新发明轮子,因此基本上如果我们有数据库,那么我们只需要o继续使用Spring Boot的解决方案。我明天将进行测试,我将给你投票:)祝贺你有了这本参考书。明天我会下载并复习。BrusselsI对此表示欢迎,但我想知道如何为每个集成类配置一个新的容器me@CHEM_Eugene您是否可以在您发布的代码中添加一个文件示例?不确定“/docker entrypoint initdb.d/init postgres.sql”的位置
应该来自哪里?这可能会覆盖image的/docker entrypoint initdb.d
,如果它已经设置好了,您如何在处理复杂数据库时添加这样的SQL并需要维护外键关系?@SQL
对我来说很好