159 votes

Exécution de PostgreSQL en mémoire uniquement

Je veux exécuter une petite base de données PostgreSQL qui fonctionne uniquement en mémoire, pour chaque test unitaire que j'écris. Par exemple :

@Before
void setUp() {
    String port = runPostgresOnRandomPort();
    connectTo("postgres://localhost:"+port+"/in_memory_db");
    // ...
}

Idéalement, j'aurai un seul exécutable postgres enregistré dans le contrôle de version, que le test unitaire utilisera.

Quelque chose comme HSQL mais pour postgres. Comment puis-je le faire ?

Où puis-je obtenir une telle version de Postgres ? Comment puis-je lui demander de ne pas utiliser le disque ?

136voto

Craig Ringer Points 72371

(Déplacement de ma réponse de Utilisation de PostgreSQL en mémoire et en le généralisant) :

Vous ne pouvez pas exécuter Pg en processus, en mémoire.

Je n'arrive pas à trouver comment faire fonctionner une base de données Postgres en mémoire pour des tests. Est-ce possible ?

Non, ce n'est pas possible. PostgreSQL est implémenté en C et compilé en code de plate-forme. À la différence de H2 ou Derby, vous ne pouvez pas simplement charger le fichier jar et le lancer comme une BD en mémoire.

Contrairement à SQLite, qui est également écrit en C et compilé en code de plate-forme, PostgreSQL ne peut pas non plus être chargé en cours de processus. Il nécessite plusieurs processus (un par connexion) car il s'agit d'une architecture multiprocessus et non multithreading. L'exigence de multiprocessing signifie que vous doit lancer le postmaster comme un processus autonome.

Au lieu de cela : préconfigurer une connexion

Je suggère d'écrire simplement vos tests pour qu'ils s'attendent à ce qu'un nom d'hôte/nom d'utilisateur/mot de passe particulier fonctionne, et de faire en sorte que le harnais de test CREATE DATABASE une base de données jetable, alors DROP DATABASE à la fin de la course. Obtenez les détails de la connexion à la base de données à partir d'un fichier de propriétés, des propriétés de la cible de construction, d'une variable d'environnement, etc.

Vous pouvez utiliser en toute sécurité une instance PostgreSQL existante dans laquelle vous avez déjà des bases de données qui vous intéressent, à condition que l'utilisateur que vous fournissez à vos tests unitaires soit no un superutilisateur, seul un utilisateur avec CREATEDB droits. Au pire, vous créerez des problèmes de performance dans les autres bases de données. Pour cette raison, je préfère utiliser une installation PostgreSQL complètement isolée pour les tests.

A la place : Lancez une instance PostgreSQL pour les tests.

Alternativement, si vous êtes vraiment vous pourriez que votre harnais de test localise le initdb y postgres binaires, exécutez initdb pour créer une base de données, modifier pg_hba.conf à trust , courir postgres pour le démarrer sur un port aléatoire, créer un utilisateur, créer une base de données, et exécuter les tests . Vous pouvez même regrouper les binaires PostgreSQL pour plusieurs architectures dans un jar et décompresser ceux de l'architecture actuelle dans un répertoire temporaire avant d'exécuter les tests.

Personnellement, je pense que c'est un problème majeur qui devrait être évité ; il est beaucoup plus facile d'avoir simplement une base de données de test configurée. Cependant, c'est devenu un peu plus facile avec l'arrivée de include_dir soutien en postgresql.conf Maintenant, vous pouvez simplement ajouter une ligne, puis écrire un fichier de configuration généré pour tout le reste.

Tests plus rapides avec PostgreSQL

Pour plus d'informations sur la manière de en toute sécurité améliorer les performances de PostgreSQL à des fins de test, voir une réponse détaillée que j'ai écrite sur ce sujet précédemment : Optimiser PostgreSQL pour des tests rapides

Le dialecte PostgreSQL de H2 n'est pas un véritable substitut.

Certaines personnes utilisent plutôt la base de données H2 en mode dialecte PostgreSQL pour exécuter des tests. Je pense que c'est presque aussi mauvais que les gens de Rails qui utilisent SQLite pour les tests et PostgreSQL pour le déploiement en production.

H2 supporte certaines extensions de PostgreSQL et émule le dialecte PostgreSQL. Cependant, il ne s'agit que d'une émulation. Vous trouverez des zones où H2 accepte une requête mais où PostgreSQL ne l'accepte pas, où le comportement diffère, etc. . Vous trouverez également de nombreux endroits où PostgreSQL permet de faire quelque chose que H2 ne peut pas faire - comme les fonctions de fenêtre, au moment où nous écrivons ces lignes.

Si vous comprenez les limites de cette approche et que l'accès à votre base de données est simple, H2 peut convenir. Mais dans ce cas, vous êtes probablement un meilleur candidat pour un ORM qui abstrait la base de données parce que vous n'utilisez pas ses fonctionnalités intéressantes de toute façon - et dans ce cas, vous n'avez plus à vous soucier autant de la compatibilité avec la base de données.

Les tablespaces ne sont pas la solution !

Faites no utiliser un tablespace pour créer une base de données "en mémoire". Non seulement ce n'est pas nécessaire, car cela n'améliore pas les performances de manière significative, mais c'est également un excellent moyen de perturber l'accès à toute autre base de données dont vous pourriez avoir besoin dans la même installation PostgreSQL. La documentation de la version 9.4 contient désormais l'avertissement suivant :

AVERTISSEMENT

Même s'il est situé en dehors du répertoire de données principal de PostgreSQL, tablespaces font partie intégrante du cluster de base de données et ne peuvent pas être base de données et ne peuvent être traités comme une collection autonome de fichiers de données. Ils sont dépendants des métadonnées contenues dans le répertoire de données principal, et ne peuvent donc pas être attachés à un cluster de bases de données différent ou sauvegardés individuellement. De même, si vous perdez un tablespace (suppression de fichiers, panne de disque, etc.), le cluster de bases de données peut devenir illisible ou incapable de démarrer. Placer un tablespace sur un système de fichiers temporaire comme un ramdisk risque de compromettre la fiabilité de tout le cluster. la fiabilité de l'ensemble du cluster.

parce que j'ai remarqué que trop de gens faisaient ça et avaient des problèmes.

(Si vous avez fait ça, vous pouvez mkdir le répertoire de tablespace manquant pour que PostgreSQL redémarre, puis DROP les bases de données, les tables, etc. manquantes. Il est préférable de ne pas le faire).

71voto

Erwin Brandstetter Points 110228

Ou vous pouvez créer un TABLESPACE dans un ramfs / tempfs et créer tous vos objets là.
On m'a récemment indiqué un article sur la façon de faire exactement cela sous Linux. Le lien original est mort. Mais il a été archivé (fourni par Arsinclair) :

Avertissement

Cela peut mettre en danger l'intégrité de votre cluster de base de données complet .
Lisez l'avertissement supplémentaire dans le manuel.
Il s'agit donc d'une option uniquement pour les données consommables.

Pour Test unitaire cela devrait fonctionner parfaitement. Si vous exécutez d'autres bases de données sur la même machine, veillez à utiliser un cluster de bases de données distinct (qui possède son propre port) pour plus de sécurité.

56voto

a_horse_with_no_name Points 100769

Ce n'est pas possible avec Postgres. Il n'offre pas de moteur en cours de traitement/en mémoire comme HSQLDB ou MySQL.

Si vous voulez créer un environnement autonome, vous pouvez peut mettre les binaires Postgres dans SVN (mais c'est plus qu'un simple exécutable).

Vous devrez exécuter initdb pour configurer votre base de données de test avant que vous puissiez faire quoi que ce soit avec ceci. Cela peut être fait à partir d'un fichier batch ou en utilisant Runtime.exec(). Mais notez que initdb n'est pas quelque chose de rapide. Vous ne voudrez certainement pas l'exécuter pour chaque test. Vous pouvez cependant l'exécuter avant votre suite de tests.

Cependant, bien que cela soit possible, je vous recommande d'avoir une installation Postgres dédiée où vous recréez simplement votre base de données de test avant d'exécuter vos tests.

Vous pouvez recréer la base de données de test en utilisant une base de données modèle qui rend sa création assez rapide (une lot plus rapide que d'exécuter initdb pour chaque test)

39voto

Rubms Points 455

Il est désormais possible d'exécuter une instance en mémoire de PostgreSQL dans vos tests JUnit via le composant Embedded PostgreSQL d'OpenTable : https://github.com/opentable/otj-pg-embedded .

En ajoutant la dépendance à la bibliothèque otj-pg-embedded ( https://mvnrepository.com/artifact/com.opentable.components/otj-pg-embedded ) vous pouvez démarrer et arrêter votre propre instance de PostgreSQL dans vos crochets @Before et @Afer :

EmbeddedPostgres pg = EmbeddedPostgres.start();

Ils proposent même une règle JUnit pour que JUnit démarre et arrête automatiquement votre serveur de base de données PostgreSQL pour vous :

@Rule
public SingleInstancePostgresRule pg = EmbeddedPostgresRules.singleInstance();

20voto

Andrejs Points 4235

Vous pourriez utiliser TestContainers pour créer un conteneur docker PosgreSQL pour les tests : http://testcontainers.viewdocs.io/testcontainers-java/usage/database_containers/

Les TestContainers fournissent un JUnit @Rule/@ClassRule ce mode démarre une base de données dans un conteneur avant vos tests et la détruit ensuite.

Ejemplo:

public class SimplePostgreSQLTest {

    @Rule
    public PostgreSQLContainer postgres = new PostgreSQLContainer();

    @Test
    public void testSimple() throws SQLException {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setJdbcUrl(postgres.getJdbcUrl());
        hikariConfig.setUsername(postgres.getUsername());
        hikariConfig.setPassword(postgres.getPassword());

        HikariDataSource ds = new HikariDataSource(hikariConfig);
        Statement statement = ds.getConnection().createStatement();
        statement.execute("SELECT 1");
        ResultSet resultSet = statement.getResultSet();

        resultSet.next();
        int resultSetInt = resultSet.getInt(1);
        assertEquals("A basic SELECT query succeeds", 1, resultSetInt);
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X