spring 用于Sping Boot 测试的嵌入式Postgres

nnt7mjpx  于 2023-03-22  发布在  Spring
关注(0)|答案(5)|浏览(127)

我正在构建一个Sping Boot 应用程序,由Postgres支持,使用Flyway进行数据库迁移。我一直遇到这样的问题,即我无法在Postgres和嵌入式单元测试数据库中生成所需的结果(即使启用了Postgres兼容模式)。所以我正在考虑使用嵌入式Postgres进行单元测试。
我遇到了an embedded postgres实现,它看起来很有前途,但不知道如何将其设置为仅在Sping Boot 的单元测试框架中运行(用于测试Spring Data存储库)。如何使用上述工具或Postgres的替代嵌入式版本来设置它?

62o28rlo

62o28rlo1#

我是@MartinVolejnik提到的embedded-database-spring-test库的作者。我认为这个库应该能满足您的所有需求(PostgreSQL + Sping Boot + Flyway +集成测试)。我真的很抱歉你遇到了一些麻烦,所以我创建了一个simple demo app,演示了如何将库与Sping Boot 框架一起使用。下面我总结了一些你需要做的基本步骤。

Maven配置

添加以下maven依赖项:

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

航路配置

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

# 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

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

示例

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

@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");
        });
    }
}
o2rvlv0m

o2rvlv0m2#

解决这个问题的另一个相当干净的方法是使用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() {
        ...
    }

依赖配置:

pom.xml

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>postgresql</artifactId>
    <scope>test</scope>
</dependency>

build.gradle

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

链接:

TestContainers - Databases
TestContainers - Postgres Module

mpgws1up

mpgws1up3#

下面的配置与Sping Boot 2.0配合良好。
embedded-database-spring-test相比,这个解决方案的优点是不会将Flyway推入类路径,这可能会扰乱Sping 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);
    }
}

玛文:

<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>

这个类基于我在这里找到的代码:https://github.com/nkoder/postgresql-embedded-example
我修改了它,使用HikariDatasource(Sping Boot 的默认值)进行正确的连接池。binariesDirdataDir用于避免重复测试中代价高昂的提取+initdb。

pexxcrt2

pexxcrt24#

看看这个:https://github.com/zonkyio/embedded-database-spring-test。需要说明的是,它是用于集成测试的。这意味着Spring上下文在单独测试期间初始化。
根据工具文档,你所需要做的就是将@AutoConfigureEmbeddedDatabase注解放在class之上:

@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>

要将它与@DataJpaTest一起使用,您需要使用注解@AutoConfigureTestDatabase(replace = NONE)禁用默认测试数据库:

@RunWith(SpringRunner.class)
@AutoConfigureTestDatabase(replace = NONE)
@AutoConfigureEmbeddedDatabase
@DataJpaTest
public class SpringDataJpaTest {
// class body...
}

为了使使用更方便,您还可以创建一个复合注解,例如:

@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...
}
czq61nw1

czq61nw15#

您可以尝试https://github.com/TouK/dockds。这会自动配置docker包含的数据库。

相关问题