用于Spring Boot Tests的嵌入式Postgres

Sin*_*hot 16 postgresql spring flyway spring-boot

我正在构建一个由Postgres支持的Spring Boot应用程序,使用Flyway进行数据库迁移.我一直在遇到无法产生迁移的问题,这些迁移在Postgres和嵌入式单元测试数据库中都会产生预期的结果(即使启用了Postgres兼容模式).所以我正在考虑使用嵌入式Postgres进行单元测试.

我遇到了一个看起来很有前景的嵌入式postgres实现,但是没有真正看到如何将其设置为仅在Spring Boot的单元测试框架中运行(用于测试Spring Data存储库).如何使用上述工具或Postgres的替代嵌入版本来设置它?

Tom*_*něk 21

我是@MartinVolejnik提到的嵌入式数据库弹簧测试库的作者.我认为该库应该满足您的所有需求(PostgreSQL + Spring Boot + Flyway +集成测试).我真的很抱歉你遇到了麻烦,所以我创建了一个简单的演示应用程序,演示了如何将库与Spring Boot框架一起使用.下面我总结了您需要做的基本步骤.

Maven配置

添加以下maven依赖项:

<dependency>
    <groupId>io.zonky.test</groupId>
    <artifactId>embedded-database-spring-test</artifactId>
    <version>1.5.2</version>
    <scope>test</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)

飞路配置

将以下属性添加到应用程序配置:

# Sets the schemas managed by Flyway -> change the xxx value to the name of your schema
# flyway.schemas=xxx // for spring boot 1.x.x
spring.flyway.schemas=xxx // for spring boot 2.x.x
Run Code Online (Sandbox Code Playgroud)

此外,请确保您不使用org.flywaydb.test.junit.FlywayTestExecutionListener.因为库具有自己的测试执行侦听器,可以优化数据库初始化,如果FlywayTestExecutionListener应用此优化,则此优化不起作用.

Spring Boot 2配置

从Spring Boot 2开始,Hibernate和Postgres Driver存在兼容性问题.因此,您可能需要将以下属性添加到应用程序配置中以修复该问题:

# Workaround for a compatibility issue of Spring Boot 2 with Hibernate and Postgres Driver
# See https://github.com/spring-projects/spring-boot/issues/12007
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
Run Code Online (Sandbox Code Playgroud)

演示嵌入式数据库使用的测试类示例:

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureEmbeddedDatabase
public class SpringDataJpaAnnotationTest {

    @Autowired
    private PersonRepository personRepository;

    @Test
    public void testEmbeddedDatabase() {
        Optional<Person> personOptional = personRepository.findById(1L);

        assertThat(personOptional).hasValueSatisfying(person -> {
            assertThat(person.getId()).isNotNull();
            assertThat(person.getFirstName()).isEqualTo("Dave");
            assertThat(person.getLastName()).isEqualTo("Syer");
        });
    }
}
Run Code Online (Sandbox Code Playgroud)


mag*_*ter 6

该问题的另一个非常干净的解决方案是使用TestContainers库。唯一需要注意的是它需要 Docker。

集成测试:

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(initializers = {ApplicationTestsIT.Initializer.class})
public class ApplicationTestsIT {

    private static int POSTGRES_PORT = 5432;

    @Autowired
    private FooRepository fooRepository;

    @ClassRule
    public static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres")
            .withDatabaseName("foo")
            .withUsername("it_user")
            .withPassword("it_pass")
            .withInitScript("sql/init_postgres.sql");

    static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            TestPropertyValues.of(
                    "spring.data.postgres.host=" + postgres.getContainerIpAddress(),
                    "spring.data.postgres.port=" + postgres.getMappedPort(POSTGRES_PORT),
                    "spring.data.postgres.username=" + postgres.getUsername(),
                    "spring.data.postgres.password=" + postgres.getPassword()
            ).applyTo(configurableApplicationContext.getEnvironment());
        }
    }

    @Test
    public void fooRepositoryTestIT() {
        ...
    }
Run Code Online (Sandbox Code Playgroud)

依赖配置
pom.xml::

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>postgresql</artifactId>
    <scope>test</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)

build.gradle

testCompile "org.testcontainers:postgresql:x.x.x"
Run Code Online (Sandbox Code Playgroud)

链接:
TestContainers - 数据库
TestContainers - Postgres 模块