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

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

36
SingleShot 24 Фев 2018 в 00:52

4 ответа

Лучший ответ

Я являюсь автором библиотеки встроенных баз данных-пружинных испытаний, которая была упомянутый @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>

Конфигурация 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");
        });
    }
}
27
Tomáš Vaněk 27 Ноя 2019 в 21:46

Приведенная ниже конфигурация хорошо работает с 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);
    }
}

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 -вложено - пример

Я изменил его, чтобы использовать HikariDatasource (по умолчанию Spring Boot) для правильного пула соединений. binariesDir и dataDir используются, чтобы избежать дорогостоящего извлечения + initdb в повторных тестах.

4
Mateusz Stefek 3 Июл 2018 в 22:20

Другим достаточно чистым решением этой проблемы является использование библиотеки 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>

{{Х0}} :

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

< STRONG> Ссылки:
TestContainers - Базы данных
TestContainers - модуль Postgres

1
magiccrafter 21 Дек 2019 в 22:56

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

0
Tomasz Wielga 26 Фев 2018 в 21:48