用于Spring启动测试的嵌入式Postgres

用于Spring启动测试的嵌入式Postgres,spring,postgresql,spring-boot,flyway,Spring,Postgresql,Spring Boot,Flyway,我正在构建一个由Postgres支持的Spring Boot应用程序,使用Flyway进行数据库迁移。我遇到了一些问题,无法在Postgres和嵌入式单元测试数据库(即使启用了Postgres兼容模式)中生成所需结果的迁移。因此,我正在考虑使用嵌入式Postgres进行单元测试 我遇到了看起来很有希望的实现,但并没有真正看到如何将其设置为仅在SpringBoot的单元测试框架中运行(用于测试Spring数据存储库)。如何使用上述工具或Postgres的替代嵌入式版本进行设置。要清楚的是,它是用于

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

我遇到了看起来很有希望的实现,但并没有真正看到如何将其设置为仅在SpringBoot的单元测试框架中运行(用于测试Spring数据存储库)。如何使用上述工具或Postgres的替代嵌入式版本进行设置。要清楚的是,它是用于集成测试的。这意味着Spring上下文在单独测试期间被初始化

根据工具文档,您只需将
@AutoConfigureEmbeddedDatabase
注释放置在类上方:

@RunWith(SpringRunner.class)
@AutoConfigureEmbeddedDatabase
@ContextConfiguration("/path/to/app-config.xml")
public class FlywayMigrationIntegrationTest {

    @Test
    @FlywayTest(locationsForMigrate = "test/db/migration")
    public void testMethod() {
        // method body...
    }
}
并添加Maven依赖项:

<dependency>
  <groupId>io.zonky.test</groupId>
  <artifactId>embedded-database-spring-test</artifactId>
  <version>1.1.0</version>
  <scope>test</scope>
</dependency>
为了使使用更舒适,您还可以创建一个复合注释,例如:

@Documented
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@AutoConfigureTestDatabase(replace = NONE)
@AutoConfigureEmbeddedDatabase
@DataJpaTest
public @interface PostgresDataJpaTest {
}
…然后在您的测试类上面使用它:

@RunWith(SpringRunner.class)
@PostgresDataJpaTest // custom composite annotation
public class SpringDataJpaTest {
// class body...
}
你可以试试。这将自动配置包含docker的数据库。

我是@MartinVolejnik提到的库的作者。我认为该库应该满足您的所有需求(PostgreSQL+Spring Boot+Flyway+集成测试)。我真的很抱歉您遇到了一些麻烦,所以我创建了一个示例来演示该库与Spring引导框架的使用。下面我总结了您需要执行的基本步骤

Maven配置

添加以下maven依赖项:

<dependency>
  <groupId>io.zonky.test</groupId>
  <artifactId>embedded-database-spring-test</artifactId>
  <version>1.1.0</version>
  <scope>test</scope>
</dependency>

io.zonky.test
嵌入式数据库spring测试
1.5.2
测试
飞道配置

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

#设置Flyway管理的模式->将xxx值更改为模式名称
#flyway.schemas=xxx//用于spring boot 1.x.x
spring.flyway.schemas=xxx//用于spring boot 2.x.x
此外,请确保不要使用
org.flywaydb.test.junit.FlywayTestExecutionListener
。因为库有自己的测试执行侦听器,可以优化数据库初始化,如果应用了
FlywayTestExecutionListener
,此优化将无效

Spring Boot 2配置

自SpringBoot2以来,Hibernate和Postgres驱动程序存在兼容性问题。因此,您可能需要将以下属性添加到应用程序配置中以修复此问题:

#解决Spring Boot 2与Hibernate和Postgres驱动程序的兼容性问题
#看https://github.com/spring-projects/spring-boot/issues/12007
spring.jpa.properties.hibernate.jdbc.lob.non_context_creation=true
示例

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

@RunWith(SpringRunner.class)
@DataJpaTest
@自动配置嵌入数据库
公共类SpringDataJpaAnnotationTest{
@自动连线
个人知识库;
@试验
public void testEmbeddedDatabase(){
Optional personOptional=personRepository.findById(1L);
assertThat(personOptional)。hasvaluesapping(person->{
assertThat(person.getId()).isNotNull();
assertThat(person.getFirstName()).isEqualTo(“Dave”);
assertThat(person.getLastName()).isEqualTo(“Syer”);
});
}
}

以下配置适用于Spring Boot 2.0

与之相比的优点是,此解决方案不会将Flyway推到类路径中,可能会破坏Spring Boot的自动配置

@Configuration
@Slf4j
public class EmbeddedPostgresConfiguration {

    @Bean(destroyMethod = "stop")
    public PostgresProcess postgresProcess() throws IOException {
        log.info("Starting embedded Postgres");

        String tempDir = System.getProperty("java.io.tmpdir");
        String dataDir = tempDir + "/database_for_tests";
        String binariesDir = System.getProperty("java.io.tmpdir") + "/postgres_binaries";

        PostgresConfig postgresConfig = new PostgresConfig(
                Version.V10_3,
                new AbstractPostgresConfig.Net("localhost", Network.getFreeServerPort()),
                new AbstractPostgresConfig.Storage("database_for_tests", dataDir),
                new AbstractPostgresConfig.Timeout(60_000),
                new AbstractPostgresConfig.Credentials("bob", "ninja")
        );

        PostgresStarter<PostgresExecutable, PostgresProcess> runtime =
                PostgresStarter.getInstance(EmbeddedPostgres.cachedRuntimeConfig(Paths.get(binariesDir)));
        PostgresExecutable exec = runtime.prepare(postgresConfig);
        PostgresProcess process = exec.start();

        return process;
    }

    @Bean(destroyMethod = "close")
    @DependsOn("postgresProcess")
    DataSource dataSource(PostgresProcess postgresProcess) {
        PostgresConfig postgresConfig = postgresProcess.getConfig();

        val config = new HikariConfig();
        config.setUsername(postgresConfig.credentials().username());
        config.setPassword(postgresConfig.credentials().password());
        config.setJdbcUrl("jdbc:postgresql://localhost:" + postgresConfig.net().port() + "/" + postgresConfig.storage().dbName());

        return new HikariDataSource(config);
    }
}
@配置
@Slf4j
公共类嵌入Postgres配置{
@Bean(destromethod=“stop”)
公共PostgresProcess PostgresProcess()引发IOException{
log.info(“启动嵌入式Postgres”);
字符串tempDir=System.getProperty(“java.io.tmpdir”);
字符串dataDir=tempDir+“/database\u用于测试”;
字符串binariesDir=System.getProperty(“java.io.tmpdir”)+“/postgres_binaries”;
PostgresConfig PostgresConfig=新的PostgresConfig(
V10_3版本,
新的AbstractPostgresConfig.Net(“localhost”,Network.getFreeServerPort()),
新的AbstractPostgresConfig.Storage(“用于测试的数据库”,dataDir),
新的AbstractPostgresConfig.Timeout(60_000),
新的AbstractPostgresConfig.Credentials(“鲍勃”,“忍者”)
);
PostgressStarter运行时=
getInstance(EmbeddedPostgres.cachedRuntimeConfig(path.get(binariesDir));
postgresecuctable exec=runtime.prepare(postgresConfig);
PostgresProcess进程=exec.start();
返回过程;
}
@Bean(destromethod=“close”)
@DependsOn(“后期处理”)
数据源数据源(PostgresProcess PostgresProcess){
PostgresConfig PostgresConfig=postgresProcess.getConfig();
val config=new HikariConfig();
config.setUsername(postgresConfig.credentials().username());
config.setPassword(postgresConfig.credentials().password());
setJdbcUrl(“jdbc:postgresql://localhost:“+postgresConfig.net().port()+”/“+postgresConfig.storage().dbName());
返回新的HikariDataSource(配置);
}
}
马文:

        <dependency>
            <groupId>ru.yandex.qatools.embed</groupId>
            <artifactId>postgresql-embedded</artifactId>
            <version>2.9</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
        </dependency>

ru.yandex.qatools.embed


我将其修改为使用
HikariDatasource
(Spring Boot的默认设置)来实现正确的连接池。
binariesDir
dataDir
用于避免重复测试中代价高昂的提取+initdb。

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

集成测试:

@RunWi
testCompile "org.testcontainers:postgresql:x.x.x"