使用 Spring Boot 和 Liquibase 时如何在每次集成测试后清理数据库表?
How to clean database tables after each integration test when using Spring Boot and Liquibase?
我有一个副项目,我正在使用 Spring Boot、Liquibase 和 Postgres。
我有以下测试顺序:
test1();
test2();
test3();
test4();
在这四个测试中,我创建了同一个实体。由于我没有在每个测试用例之后从 table 中删除记录,因此出现以下异常:org.springframework.dao.DataIntegrityViolationException
我想通过以下约束解决这个问题:
- 我不想使用
@repository
清理数据库。
- 我不想终止数据库并在每个测试用例上创建它,因为我正在使用 TestContainers 并且这样做会增加完成测试所需的时间。
简而言之:如何在每个测试用例之后从一个或多个 table 秒中删除记录,而无需 1) 使用每个实体的 @repository
和 2) 终止并启动数据库容器在每个测试用例上?
我发现执行此操作的最简单方法如下:
- 注入一个 JdbcTemplate 实例
@Autowired
private JdbcTemplate jdbcTemplate;
- 使用 class JdbcTestUtils 从您需要的表中删除记录。
JdbcTestUtils.deleteFromTables(jdbcTemplate, "table1", "table2", "table3");
- 在您的测试中用
@After
或 @AfterEach
注释的方法中调用此行 class:
@AfterEach
void tearDown() throws DatabaseException {
JdbcTestUtils.deleteFromTables(jdbcTemplate, "table1", "table2", "table3");
}
我在这个博客中找到了这种方法 post:
Easy Integration Testing With Testcontainers
您可以在测试方法上使用@Transactional。这样,每个测试方法都将 运行 在其自己的事务括号内,并在下一个测试方法 运行.
之前回滚
当然,这只有在您没有对手动事务管理做任何奇怪的事情时才有效,并且它依赖于一些 Spring 引导自动配置魔法,因此可能无法在每个用例中使用,但是它通常是一种高性能且非常简单的隔离测试用例的方法。
用 @DataJpaTest
注释您的测试 class。来自文档:
By default, tests annotated with @DataJpaTest are transactional and roll back at the end of each test. They also use an embedded in-memory database (replacing any explicit or usually auto-configured DataSource).
例如使用 Junit4:
@RunWith(SpringRunner.class)
@DataJpaTest
public class MyTest {
//...
}
使用 Junit5:
@DataJpaTest
public class MyTest {
//...
}
我认为这是 postgreSQL 最有效的方式。您可以为其他数据库做同样的事情。只需找到如何重新启动表序列并执行它
@Autowired
private JdbcTemplate jdbcTemplate;
@AfterEach
public void execute() {
jdbcTemplate.execute("TRUNCATE TABLE users" );
jdbcTemplate.execute("ALTER SEQUENCE users_id_seq RESTART");
}
我个人的偏好是:
private static final String CLEAN_TABLES_SQL[] = {
"delete from table1",
"delete from table2",
"delete from table3"
};
@After
public void tearDown() {
for (String query : CLEAN_TABLES_SQL)
{
getJdbcTemplate().execute(query);
}
}
要采用这种方法,您需要
使用 DaoSupport 扩展 class,并在构造函数中设置数据源。
public class Test extends NamedParameterJdbcDaoSupport
public Test(DataSource dataSource)
{
setDataSource(dataSource);
}
我有一个副项目,我正在使用 Spring Boot、Liquibase 和 Postgres。
我有以下测试顺序:
test1();
test2();
test3();
test4();
在这四个测试中,我创建了同一个实体。由于我没有在每个测试用例之后从 table 中删除记录,因此出现以下异常:org.springframework.dao.DataIntegrityViolationException
我想通过以下约束解决这个问题:
- 我不想使用
@repository
清理数据库。 - 我不想终止数据库并在每个测试用例上创建它,因为我正在使用 TestContainers 并且这样做会增加完成测试所需的时间。
简而言之:如何在每个测试用例之后从一个或多个 table 秒中删除记录,而无需 1) 使用每个实体的 @repository
和 2) 终止并启动数据库容器在每个测试用例上?
我发现执行此操作的最简单方法如下:
- 注入一个 JdbcTemplate 实例
@Autowired
private JdbcTemplate jdbcTemplate;
- 使用 class JdbcTestUtils 从您需要的表中删除记录。
JdbcTestUtils.deleteFromTables(jdbcTemplate, "table1", "table2", "table3");
- 在您的测试中用
@After
或@AfterEach
注释的方法中调用此行 class:
@AfterEach
void tearDown() throws DatabaseException {
JdbcTestUtils.deleteFromTables(jdbcTemplate, "table1", "table2", "table3");
}
我在这个博客中找到了这种方法 post: Easy Integration Testing With Testcontainers
您可以在测试方法上使用@Transactional。这样,每个测试方法都将 运行 在其自己的事务括号内,并在下一个测试方法 运行.
之前回滚当然,这只有在您没有对手动事务管理做任何奇怪的事情时才有效,并且它依赖于一些 Spring 引导自动配置魔法,因此可能无法在每个用例中使用,但是它通常是一种高性能且非常简单的隔离测试用例的方法。
用 @DataJpaTest
注释您的测试 class。来自文档:
By default, tests annotated with @DataJpaTest are transactional and roll back at the end of each test. They also use an embedded in-memory database (replacing any explicit or usually auto-configured DataSource).
例如使用 Junit4:
@RunWith(SpringRunner.class)
@DataJpaTest
public class MyTest {
//...
}
使用 Junit5:
@DataJpaTest
public class MyTest {
//...
}
我认为这是 postgreSQL 最有效的方式。您可以为其他数据库做同样的事情。只需找到如何重新启动表序列并执行它
@Autowired
private JdbcTemplate jdbcTemplate;
@AfterEach
public void execute() {
jdbcTemplate.execute("TRUNCATE TABLE users" );
jdbcTemplate.execute("ALTER SEQUENCE users_id_seq RESTART");
}
我个人的偏好是:
private static final String CLEAN_TABLES_SQL[] = {
"delete from table1",
"delete from table2",
"delete from table3"
};
@After
public void tearDown() {
for (String query : CLEAN_TABLES_SQL)
{
getJdbcTemplate().execute(query);
}
}
要采用这种方法,您需要 使用 DaoSupport 扩展 class,并在构造函数中设置数据源。
public class Test extends NamedParameterJdbcDaoSupport
public Test(DataSource dataSource)
{
setDataSource(dataSource);
}