我正在测试TestContainers,我想知道如何填充执行.sql文件的数据库来创建结构并添加一些行。
怎么做?
@Rule
public PostgreSQLContainer postgres = new PostgreSQLContainer();
提前谢谢了
Juan Antonio
使用Spring Boot时,我发现最简单的方法是使用TestContainers的JDBC URL支持。
您可以创建一个application-integration-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
请注意JDBC URL中的:tc
部分。
您现在可以编写如下单元测试:
@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.
}
注意:这在Practical Guide to Building an API Back End with Spring Boot第7章中有更详细的解释(免责声明:我是本书的作者)
Spring框架提供了为测试套件或测试单元执行SQL脚本的能力。例如:
@Test
@Sql({"/test-schema.sql", "/test-user-data.sql"})
public void userTest {
// execute code that relies on the test schema and test data
}
您还可以查看Spring Test DBUnit,它提供注释以填充测试单元的数据库。它使用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
}
此外,您还可以查看DbSetup,它提供了一个java流畅的DSL来填充您的数据库。
你可以使用DatabaseRider,它在幕后使用DBUnit,用于填充测试数据库和TestContainers作为测试数据源。以下是一个示例测试,github here上提供了完整的源代码。
@RunWith(SpringRunner.class)
@SpringBootTest
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ActiveProfiles("integration-test")
@DBRider //enables database rider in spring tests
@DBUnit(caseInsensitiveStrategy = Orthography.LOWERCASE) //https://stackoverflow.com/questions/43111996/why-postgresql-does-not-like-uppercase-table-names
public class SpringBootDBUnitIt {
private static final PostgreSQLContainer postgres = new PostgreSQLContainer(); //creates the database for all tests on this file
@PersistenceContext
private EntityManager entityManager;
@Autowired
private UserRepository userRepository;
@BeforeClass
public static void setupContainer() {
postgres.start();
}
@AfterClass
public static void shutdown() {
postgres.stop();
}
@Test
@DataSet("users.yml")
public void shouldListUsers() throws Exception {
assertThat(userRepository).isNotNull();
assertThat(userRepository.count()).isEqualTo(3);
assertThat(userRepository.findByEmail("[email protected]")).isEqualTo(new User(3));
}
@Test
@DataSet("users.yml") //users table will be cleaned before the test because default seeding strategy
@ExpectedDataSet("expected_users.yml")
public void shouldDeleteUser() throws Exception {
assertThat(userRepository).isNotNull();
assertThat(userRepository.count()).isEqualTo(3);
userRepository.delete(userRepository.findOne(2L));
entityManager.flush();//can't SpringBoot autoconfigure flushmode as commit/always
//assertThat(userRepository.count()).isEqualTo(2); //assertion is made by @ExpectedDataset
}
@Test
@DataSet(cleanBefore = true)//as we didn't declared a dataset DBUnit wont clear the table
@ExpectedDataSet("user.yml")
public void shouldInsertUser() throws Exception {
assertThat(userRepository).isNotNull();
assertThat(userRepository.count()).isEqualTo(0);
userRepository.save(new User("[email protected]", "new user"));
entityManager.flush();//can't SpringBoot autoconfigure flushmode as commit/always
//assertThat(userRepository.count()).isEqualTo(1); //assertion is made by @ExpectedDataset
}
}
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/datasets/users.yml
users:
- ID: 1
EMAIL: "[email protected]"
NAME: "dbunit"
- ID: 2
EMAIL: "[email protected]"
NAME: "rmpestano"
- ID: 3
EMAIL: "[email protected]"
NAME: "springboot"
src/test/resources/datasets/expected_users.yml
users:
- ID: 1
EMAIL: "[email protected]"
NAME: "dbunit"
- ID: 3
EMAIL: "[email protected]"
NAME: "springboot"
src/test/resources/datasets/user.yml
users:
- ID: "regex:\\d+"
EMAIL: "[email protected]"
NAME: "new user"
经过一些评论,我认为回顾一下Spring Data JDBC中使用Test Containers的例子很有意思:
注意:使用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 ....")
。