web-dev-qa-db-fra.com

Le mode postgresql H2 ne fonctionne pas pour moi

Salut, mon application accède à la base de données Postgres et j'ai de nombreuses requêtes prédéfinies (Rank, Parition, jointure complexe, etc.) que je lance contre Postgres. Maintenant, je veux opter pour le test unitaire de ces comportements de requêtes avec de petites données de test. J'ai donc commencé avec H2/Junit. J'ai découvert que la plupart des requêtes Postgres comme Rank, Partition, Complex case lors de la mise à jour, etc. J'ai donc pensé à utiliser le mode de compatibilité H2 PosgreSQL en pensant que toutes les requêtes postgres fonctionneraient sur H2, corrigez-moi si je me trompe.

J'ai suivi la documentation de H2 disant Pour utiliser le mode PostgreSQL, utilisez l'URL de base de données jdbc: h2: ~/test; MODE = PostgreSQL ou l'instruction SQL SET MODE PostgreSQL.

J'ai activé le mode en utilisant SET MODE PostgreSQL et j'ai essayé de lancer une des requêtes qui implique rank () et fonctionne en postgres mais cela n'a pas fonctionné H2. Cela me donne l'exception suivante

Function "RANK' not found; in SQL statement

Veuillez guider Je suis nouveau dans les tests de H2 et de base de données. Merci d'avance. J'utilise le pilote H2 jdbc pour lancer des requêtes postgres en pensant que le mode de compatibilité H2 Posgress me permettra de lancer des requêtes postgres.

20
Umesh K

J'ai donc pensé à utiliser le mode de compatibilité H2 PosgreSQL en pensant que toutes les requêtes postgres fonctionneraient sur H2, veuillez me corriger si je me trompe

J'ai bien peur que ce ne soit pas vrai.

H2 essaie d'émuler la syntaxe PostgreSQL et de prendre en charge quelques fonctionnalités et extensions. Cela ne correspondra jamais complètement au comportement de PostgreSQL et ne prend pas en charge toutes les fonctionnalités.

Les seules options dont vous disposez sont:

  • Utilisez PostgreSQL dans les tests; ou
  • Ne plus utiliser de fonctionnalités non prises en charge par H2

Je suggère d'utiliser Pg pour les tests. Il est relativement simple d'écrire un harnais de test qui initdb est une instance postgres et le lance pour le tester puis le détruit après.

Mise à jour basée sur les commentaires:

Il n'y a pas de ligne dure entre les tests "unitaires" et "d'intégration". Dans ce cas, H2 est également un composant externe. Les tests unitaires puristes auraient un répondeur factice aux requêtes dans le cadre du harnais de test. Tester contre H2 est tout autant un test "d'intégration" que tester contre PostgreSQL. Le fait qu'il soit en cours et en mémoire est une commodité, mais n'est pas fonctionnel.

Si vous voulez test unitaire , vous devez écrire une autre cible de base de données pour votre application pour accompagner vos cibles "PostgreSQL", "SybaseIQ", etc. Appelez-le, disons, "MockDatabase". Cela devrait simplement renvoyer les résultats attendus des requêtes. Il n'exécute pas vraiment les requêtes, il n'existe que pour tester le comportement du reste du code.

Personnellement, je pense que c'est une énorme perte de temps, mais c'est ce qu'un puriste de test unitaire ferait pour éviter d'introduire des dépendances externes dans le faisceau de test.

Si vous insistez pour avoir des tests unitaires (par opposition à l'intégration) pour vos composants de base de données mais que vous ne pouvez/ne voulez pas écrire une interface factice, vous devez plutôt trouver un moyen d'utiliser une interface existante. H2 serait un candidat raisonnable pour cela - mais vous devrez écrire un nouveau backend avec un nouvel ensemble de requêtes qui fonctionnent pour H2, vous ne pouvez pas simplement réutiliser votre backend PostgreSQL. Comme nous l'avons déjà établi, H2 ne prend pas en charge toutes les fonctionnalités que vous devez utiliser avec PostgreSQL, vous devrez donc trouver différentes façons de faire les mêmes choses avec H2. Une option serait de créer une base de données H2 simple avec des résultats "attendus" et des requêtes simples qui renvoient ces résultats, ignorant complètement le schéma de l'application réelle. Le seul véritable inconvénient ici est que cela peut être très difficile à maintenir ... mais ce sont des tests unitaires.

Personnellement, je testerais simplement avec PostgreSQL. À moins que je teste des classes ou des modules individuels qui sont autonomes en tant qu'unités bien définies à interface étroite, peu m'importe si quelqu'un l'appelle un test "unitaire" ou "d'intégration". Je vais tester, disons, les classes de validation des données. Pour les tests unitaires puristes du code d'interface de base de données, cela n'a pas beaucoup de sens et je vais juste faire des tests d'intégration.

Bien qu'il soit pratique d'avoir une base de données en mémoire en cours, cela n'est pas nécessaire. Vous pouvez écrire votre faisceau de test pour que le code de configuration initdb soit un nouveau PostgreSQL et le lance; puis le code de suppression tue le postmaster et supprime le datadir. J'ai écrit plus à ce sujet dans cette réponse .

Voir également:

Pour ce qui est de:

Si toutes les requêtes avec les jeux de données finaux attendus fonctionnent correctement dans Postgress, je peux supposer que cela fonctionnera correctement dans tous les autres dbs

Si je comprends bien ce que vous dites, alors oui, c'est le cas - si le reste de votre code fonctionne avec un ensemble de données de PostgreSQL, il devrait généralement fonctionne de la même manière avec un ensemble de données contenant les mêmes données d'une autre base de données. Tant qu'il utilise des types de données simples et non des fonctionnalités spécifiques à la base de données, bien sûr.

34
Craig Ringer