我正在寻找一种方法来保持组件测试的独立性。 因此,为了实现这种行为,在某些测试中我需要有一个“干净的数据库”或至少一个“干净的表”。我仍然找不到在测试容器内执行此操作的方法。 所以这是我到目前为止所尝试过的: 我的容器设置类:
公共类 PostgreSqlTestContainer 实现 QuarkusTestResourceLifecycleManager {
public static final PostgreSQLContainer<?> POSTGRES = new PostgreSQLContainer<>("postgres:alpine");
@Override
public Map<String, String> start() {
POSTGRES.start();
return some_db_config_as_per_doc;
}
@Override
public void stop() {
POSTGRES.stop();
}
这是测试类:
@QuarkusTest
@QuarkusTestResource(PostgreSqlTestContainer.class)
class UserResourcesTest {
@Test
scenario_one(){
// create a new user
// do some stuff (@POST.. check HTTP == 201)
}
@Test
scenario_two(){
// create new user
// do some stuff (@POST.. check HTTP == 201) (pass)
// look for all users on database
// do more stuff (@GET.. check HTTP == 200) (pass)
// assert that only 1 user was found
// since scenario_one should not interfere with scenario_two (fail)
}
}
第二个场景失败,因为第一个测试中的一些“脏”仍然在数据库容器上。 我尝试为每个测试停止/启动容器。 (过程非常非常慢,有时我会收到错误,然后又非常慢)。
@BeforeEach
void setup(){
PostgreSqlTestContainer.POSTGRES.stop();
PostgreSqlTestContainer.POSTGRES.start();
}
还尝试截断表/删除整个数据库:
@Inject
EntityManager entityManager;
@BeforeEach
private void rollBack(){
truncate();
}
void truncate(){
Query nativeQuery = entityManager.createNativeQuery("DROP DATABASE IF EXISTS db_name");
nativeQuery.executeUpdate();
}
我正在寻找解决此问题的方法,我只是想在每次测试之前使用
@BeforeEach
来清理数据库。我的意思是,我想要的只是每次测试都有一个干净的环境。
创建一个名为
test_template
的模板测试数据库。
每次测试后,
断开所有会话与测试数据库的连接(PostgreSQL v13 不需要):
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'test';
使用
删除数据库DROP DATABASE test;
在 v13 中,使用附加的
FORCE
选项。
使用
创建一个新的测试数据库CREATE DATABASE test TEMPLATE test_template;
注意:您必须在 JDBC 驱动程序中启用自动提交才能使
CREATE DATABASE
和 DROP DATABASE
正常工作。
你可以尝试一下:
从容器定义中删除 static 子句它将强制它在每次 start() 执行时创建容器。
PostgreSQLContainer POSTGRES ....
你也可以删除@beforeach中的停止我认为这是没有必要的
您可以在启动提供模式sql的容器时创建表:
PostgreSQLContainer<?> postgresContainer = new PostgreSQLContainer< ("postgres:14-alpine")
.withDatabaseName("db")
.withUsername("username")
.withPassword("password")
.withCopyFileToContainer(
MountableFile.forClasspathResource("/schema.sql"),
"/docker-entrypoint-initdb.d/"
);
如果您想根据您的测试方法插入一些数据,您可以执行类似的操作并在测试开始时调用它:
private void loadData(String scriptPath) {
try {
postgresContainer.copyFileToContainer(
MountableFile.forClasspathResource(scriptPath),
"/data/import.sql"
);
postgresContainer.execInContainer(
"psql",
"-U",
postgresContainer.getUsername(),
"-d",
postgresContainer.getDatabaseName(),
"-f",
"/data/import.sql"
);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}