web-dev-qa-db-fra.com

Postgres intégré pour les tests de démarrage du printemps

Je construis une application Spring Boot, soutenue par Postgres, utilisant Flyway pour les migrations de bases de données. Je me suis heurté à des problèmes où je ne pouvais pas produire une migration qui génère le résultat souhaité à la fois dans Postgres et dans la base de données de test d'unité intégrée (même avec le mode de compatibilité Postgres activé). Je cherche donc à utiliser Postgres intégré pour les tests unitaires.

Je suis tombé sur n postgres intégré qui semble prometteur, mais je ne vois pas vraiment comment le configurer pour qu'il s'exécute uniquement dans la structure de test unitaire de Spring Boot (pour tester les référentiels Spring Data). Comment l’organiser à l’aide de l’outil mentionné ou d’une autre version intégrée de Postgres?

15
SingleShot

Je suis l'auteur de la bibliothèque embedded-database-spring-test mentionnée par @MartinVolejnik. Je pense que la bibliothèque devrait répondre à tous vos besoins (tests d'intégration PostgreSQL + Spring Boot + Flyway +). Je suis vraiment désolée que vous rencontriez des problèmes. J'ai donc créé une application de démonstration simple qui illustre l'utilisation de la bibliothèque avec le cadre Spring Boot. Ci-dessous, j'ai résumé les étapes de base que vous devez faire.

Configuration Maven

Ajoutez la dépendance maven suivante:

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

Configuration de la voie de migration

Ajoutez la propriété suivante à la configuration de votre application:

# 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

De plus, assurez-vous de ne pas utiliser org.flywaydb.test.junit.FlywayTestExecutionListener. Parce que la bibliothèque a son propre écouteur d'exécution de test qui peut optimiser l'initialisation de la base de données et que cette optimisation n'a aucun effet si le FlywayTestExecutionListener est appliqué.

Configuration de Spring Boot 2

Depuis Spring Boot 2, il existe un problème de compatibilité avec Hibernate et Postgres Driver. Il vous faudra donc peut-être ajouter la propriété suivante à la configuration de votre application pour résoudre ce problème:

# 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

Exemple

Un exemple de classe de test démontrant l'utilisation de la base de données intégrée:

@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");
        });
    }
}
21
Tomáš Vaněk

La configuration ci-dessous fonctionne bien avec Spring Boot 2.0.

L'avantage par rapport à embedded-database-spring-test est que cette solution ne pousse pas Flyway dans le chemin de classe, ce qui risque de gâcher la configuration automatique de 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>

La classe est basée sur le code que j'ai trouvé ici: https://github.com/nkoder/postgresql-embedded-example

Je l'ai modifié pour utiliser HikariDatasource (valeur par défaut de Spring Boot) pour un regroupement correct des connexions. binariesDir et dataDir permettent d'éviter l'extraction coûteuse + initdb lors de tests répétés.

2
Mateusz Stefek

Jetez un oeil à ceci: https://github.com/zonkyio/embedded-database-spring-test . Juste pour être clair, c'est destiné aux tests d'intégration. Cela signifie que le contexte Spring est initialisé pendant le test individuel.

Selon la documentation relative aux outils, tout ce que vous avez à faire est de placer l'annotation @AutoConfigureEmbeddedDatabase Au-dessus de la classe:

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

    @Test
    @FlywayTest(locationsForMigrate = "test/db/migration")
    public void testMethod() {
        // method body...
    }
}

et ajoutez la dépendance Maven:

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

Pour l'utiliser avec @DataJpaTest, Vous devez désactiver la base de données de test par défaut à l'aide de l'annotation @AutoConfigureTestDatabase(replace = NONE):

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

Pour rendre l'utilisation plus confortable, vous pouvez également créer une annotation composite, comme par exemple:

@Documented
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@AutoConfigureTestDatabase(replace = NONE)
@AutoConfigureEmbeddedDatabase
@DataJpaTest
public @interface PostgresDataJpaTest {
}

..et utilisez-le ensuite au-dessus de votre classe de test:

@RunWith(SpringRunner.class)
@PostgresDataJpaTest // custom composite annotation
public class SpringDataJpaTest {
// class body...
}
1
Martin Volejnik

Vous pouvez essayer https://github.com/TouK/dockds . Cela configure automatiquement une base de données contenue dans le menu fixe.

0
Tomasz Wielga