我想将Testcontainers用于
@DataJpaTest
(及
@SpringBootTest
)使用JUnit5。我使用
@Testcontainers
和
@Container
注释如下:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import static org.assertj.core.api.Assertions.assertThat;
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Testcontainers
public class AtleteRepositoryTest {
@Container
private static final PostgreSQLContainer<?> CONTAINER = new PostgreSQLContainer<>("postgres:11");
@DynamicPropertySource
static void registerProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", CONTAINER::getJdbcUrl);
registry.add("spring.datasource.username", CONTAINER::getUsername);
registry.add("spring.datasource.password", CONTAINER::getPassword);
}
@Autowired
private AtleteRepository repository;
@Test
void testSave() {
repository.save(new Atlete("Wout Van Aert", 0, 1, 0));
assertThat(repository.count()).isEqualTo(1);
}
}
看见
https://github.com/wimdeblauwe/blog-example-code/tree/feature/testcontainers-datajpatest/testcontainers-datajpatest
查看完整的示例代码(
AtleteRepositoryTest
,
TeamRepositoryTest
和
TestcontainersDatajpatestApplicationTests
).
为了避免重复声明PostgreSQL容器和动态属性,我尝试了以下方法:
JUnit 5扩展
Baeldung有一个关于如何
use a JUnit 5 extension to avoid the duplication
.
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.testcontainers.containers.PostgreSQLContainer;
public class PostgreSQLExtension implements BeforeAllCallback, AfterAllCallback {
private PostgreSQLContainer<?> postgres;
@Override
public void beforeAll(ExtensionContext context) {
postgres = new PostgreSQLContainer<>("postgres:11");
postgres.start();
System.setProperty("spring.datasource.url", postgres.getJdbcUrl());
System.setProperty("spring.datasource.username", postgres.getUsername());
System.setProperty("spring.datasource.password", postgres.getPassword());
}
@Override
public void afterAll(ExtensionContext context) {
postgres.stop();
}
}
如果你只有一次测试,它是有效的,但是
不
如果同时运行多个(使用IntelliJ或Maven)。在这种情况下,其中一个测试将失败,因为无法建立与数据库的连接。
还要注意的是,这个扩展
不
使用
DynamicPropertyRegistry
,但是简单的环境变量。
看到了吗
feature/testcontainers-datajpatest_baeldung-extension
代码的分支。
使用公共超类
在树枝上
feature/testcontainers-datajpatest_database-base-test
,我尝试使用一个普通的超类:
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.PostgreSQLContainer;
public class DatabaseBaseTest {
private static final PostgreSQLContainer<?> CONTAINER = new PostgreSQLContainer<>("postgres:11");
@BeforeAll
static void start() {
CONTAINER.start();
}
@AfterAll
static void stop() {
CONTAINER.stop();
}
@DynamicPropertySource
static void registerProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", () -> {
String jdbcUrl = CONTAINER.getJdbcUrl();
System.out.println("jdbcUrl = " + jdbcUrl);
return jdbcUrl;
});
registry.add("spring.datasource.username", CONTAINER::getUsername);
registry.add("spring.datasource.password", CONTAINER::getPassword);
}
}
不幸的是,这也不起作用。我在日志中注意到
@DynamicPropertySource
带注释的方法只调用了一次,而不是每次测试,这让我尝试了选项3:
具有
@动态属性源
在子类中
当使用公共超类,但添加
@动态属性源
方法在每个子类中再次工作。
此类子类的示例代码:
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class AtleteRepositoryTest extends DatabaseBaseTest {
@DynamicPropertySource
static void registerProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", () -> {
String jdbcUrl = CONTAINER.getJdbcUrl();
System.out.println("jdbcUrl = " + jdbcUrl);
return jdbcUrl;
});
registry.add("spring.datasource.username", CONTAINER::getUsername);
registry.add("spring.datasource.password", CONTAINER::getPassword);
}
@Autowired
private AtleteRepository repository;
@Test
void testSave() {
repository.save(new Atlete("Wout Van Aert", 0, 1, 0));
assertThat(repository.count()).isEqualTo(1);
}
}
见分支
feature/testcontainers-datajpatest_database-base-test_subclasses
对于那个版本。
因此,尽管它有效,但每个测试类中仍然存在大量重复。
有没有其他避免重复的方法?