Встроенные Postgres для весенних тестов загрузки

Я создаю приложение Spring Boot, поддерживаемое Postgres, используя Flyway для миграции баз данных. Я столкнулся с проблемами, когда я не могу выполнить миграцию, которая генерирует желаемый результат как в Postgres, так и в базе данных встроенных модулей (даже если включен режим совместимости Postgres). Поэтому я рассматриваю использование встроенных Postgres для модульных тестов.

Я столкнулся с внедренной реализацией postgres, которая выглядит многообещающей, но на самом деле не вижу, как настроить ее для запуска только в рамках тестовой платформы Spring Boot (для тестирования хранилищ Spring Data). Как бы установить это с помощью упомянутого инструмента или альтернативной встроенной версии Postgres?

Ответ 1

Я являюсь автором встроенной библиотеки database-spring-test, о которой упоминал @MartinVolejnik. Я думаю, что библиотека должна отвечать всем вашим требованиям (PostgreSQL + Spring Boot + Flyway + интеграционное тестирование). Мне очень жаль, что у вас возникли проблемы, поэтому я создал простое демонстрационное приложение, которое демонстрирует использование библиотеки вместе со средой Spring Boot. Ниже я кратко изложил основные шаги, которые вам нужно сделать.

Конфигурация Maven

Добавьте следующую зависимость maven:

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

Конфигурация Flyway

Добавьте следующее свойство в конфигурацию вашего приложения:

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

Конфигурация 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

пример

Пример тестового класса, демонстрирующий использование встроенной базы данных:

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

Ответ 2

Конфигурация ниже хорошо работает с Spring Boot 2.0.

Преимущество теста embedded-database-spring-test заключается в том, что это решение не переносит 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);
    }
}

Maven:

        <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 (Spring Boot default) для правильного объединения пулов. binariesDir и dataDir используются, чтобы избежать дорогостоящей экстракции + initdb в повторных испытаниях.

Ответ 3

Взгляните на это: https://github.com/zonkyio/embedded-database-spring-test. Чтобы быть понятным, это означало интеграционное тестирование. Значение контекста 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>

Чтобы использовать его вместе с @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...
}

Ответ 4

Вы можете попробовать https://github.com/TouK/dockds. Это автоматически настраивает базу данных, содержащую докеры.