[JAVA] Test JUnit facile de la version Elasticsearch 2018 avec Embedded-elasticsearch

Elasticsearch intégré: lancez ES dans le code de test

Comment effectuez-vous des tests unitaires et d'intégration d'applications à l'aide d'Elasticsearch? Je pense qu'il existe différentes méthodes telles que la création et l'injection d'une maquette de client ES, la connexion à une instance ES exécutée en externe, etc., mais il est pratique d'utiliser la recherche Elastic intégrée uniquement pour le développement d'applications Java. La méthode existait autrefois. En d'autres termes, puisque ES lui-même est une application Java, il s'agit d'une méthode pour démarrer ensemble ES Node '' sur la JVM qui exécute le test et l'utilise comme instance ES pour les tests. Bien que ce soit pour les tests, il s'agit d'une véritable instance ES qui n'est pas une simulation, il était donc très pratique pour l'indexation et la recherche de fonctionner normalement. Elastic lui-même fournit également un modèle de test JUnit appelé ES IntegTestCase``, et j'ai écrit un article il y a quelques années.

Cependant, depuis la version 5, cette recherche Elastic Embedded est devenue de plus en plus difficile à utiliser.

Étant donné que la société a également produit un cadre de test en utilisant Embedded Elasticsearch en interne et l'a utilisé à fond, lors de la mise à niveau depuis ES2.x, un module nécessaire aux tests a été ajouté au référentiel Maven interne tout en chuchotant avec un collègue. Le travail compliqué d'enregistrement un par un est devenu nécessaire.

Il semble que d'autres personnes aient eu des problèmes similaires, et lorsque j'ai vérifié les forums élastiques, les alternatives suivantes ont été suggérées.

En bref, c'est un moyen d'exécuter une instance ES de test en conjonction avec un outil de construction. Cela peut être utilisé avec cela, mais il est facile d'exécuter des cas de test directement sur l'EDI sans passer par un outil de construction, et il est facile de contrôler les paramètres du nœud ES et le démarrage directement à partir du code de test, etc. Elasticsearch intégré De nombreux avantages de sont perdus.

Ainsi, même après ES 5.x, certaines bibliothèques ont été développées pour réaliser quelque chose comme la recherche Elastic Embedded.

`ʻElasticsearch-cluster-runner`` est une bibliothèque pour utiliser Embedded Elasticsearch même après ES5.x. Les modules ES qui n'ont pas été téléchargés sur Maven Central ont été téléchargés sur Maven Central par eux-mêmes. J'ai la tête baissée.

«« Embedded-elasticsearch »est une approche légèrement différente. Contrairement au nom `ʻembedded-elasticsearch``, cette librairie n'exécute pas ES sur la même JVM que le test. À la place, exécutez l'instance ES en tant que processus externe avec les étapes suivantes pour chaque test.

En d'autres termes, vous obtenez le même environnement que vous télécharger et exécuter normalement un ES. D'autre part, la facilité d'utilisation qui permet au contrôle du nœud ES d'être programmable à partir du code de test est similaire à la recherche Elastic intégrée.

Chacun a ses avantages et désavantages

Embedded Elasticsearch doit également démarrer ES sur la même JVM, de sorte que toutes les dépendances nécessaires pour exécuter ES sont ajoutées au chemin de classe. Par conséquent, il peut entrer en conflit avec les dépendances de l'application que vous souhaitez tester à l'origine. D'un autre côté, `ʻembedded-elasticsearch`` ne pose pas le même problème car ES est exécuté en tant que processus externe. «Embedded-elasticsearch» lui-même est très léger, ne reposant que sur Jackson et certaines bibliothèques communes.

La bouche avant est devenue plus longue, mais dans cet article, j'essaierai d'utiliser `ʻembedded-elasticsearch`` de JUnit.

Utilisation basique de `ʻembedded-elasticsearch``

Paramètre de dépendance

Ajoutez pl.allegro.tech: embedded-elasticsearch à la dépendance. La dernière version est `` 2.5.0 ''. La dernière version est recommandée car le problème sous Windows a été résolu récemment.

pom.xml


  <dependencies>
    ...
    <dependency>
      <groupId>pl.allegro.tech</groupId>
      <artifactId>embedded-elasticsearch</artifactId>
      <version>2.5.0</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.7.21</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <version>5.1.0</version>
      <scope>test</scope>
    </dependency>

  </dependencies>

```Embedded-elasticsearchutilise SLF4J pour la journalisation, mais il ne contient que slf4j-apicomme dépendance, donc s'il n'y a pas de liaison appropriée pour la dépendance, ajoutez-la également (exemple ci-dessus). Puis slf4j-simple ''). Dans cet exemple, JUnit5 est utilisé comme cadre de test, mais il peut bien sûr être utilisé avec JUnit4 et ScalaTest sans aucun problème.

Code de test

Le code de test ressemble à ceci.

public class TestEmbeddedES {

  private static EmbeddedElastic es = null;

  @BeforeAll
  public static void startES() throws Exception {
    
    es = EmbeddedElastic.builder()
      .withElasticVersion("6.2.4")
      .withSetting("discovery.zen.ping.unicast.hosts", Collections.emptyList()) // <- (*)
      .build();

    es.start();
  }

  @Test
  void check_es_status() throws IOException {

    System.out.println("HTTP port: " + es.getHttpPort());
    System.out.println("Transport port: " + es.getTransportTcpPort());

    CloseableHttpClient client = HttpClientBuilder.create().build();

    String uri = "http://localhost:" + es.getHttpPort() + "/";
    CloseableHttpResponse res = client.execute(new HttpGet(uri));
    System.out.println(IOUtils.toString(res.getEntity().getContent(), "UTF-8"));
  }

  @AfterAll
  public static void stopES() {
    es.stop();
  }

}

Créez une instance de ʻEmbedded Elastic`` en utilisant le générateur avant d'exécuter tous les tests ( `@ BeforeAll). Vous pouvez spécifier la version ES et la définir (finalement écrite dans config / elasticsearch.yml '') via le générateur. Les paramètres indiqués par (*) sont des solutions de contournement qui désactivent la découverte Zen pour ES. Si ES fonctionne sur la même machine, le nœud ES démarré pour le test peut se connecter accidentellement sans ce paramètre.

ES est lancé en appelant «EmbeddedElastic # start ()». Le numéro de port pour se connecter à l'ES démarré peut être obtenu en appelant getHttpPort () '' ou getTransportTcpPort () ''. Dans le test réel, je pense que vous allez créer un client ou définir un service à tester en utilisant ces numéros de port.

Vous devez vous rappeler d'appeler ʻEmbeddedElastic # stop () pour arrêter l'ES une fois tous les tests terminés ( @ AfterAll).

Opération de base

Lorsque le test ci-dessus est exécuté, le journal suivant est généré.

[main] INFO p.a.t.e.ElasticSearchInstaller - Downloading https://artifacts.elastic.co/.../elasticsearch-6.2.4.zip to /var/folders/pl/l3n21...
[main] INFO p.a.t.e.ElasticSearchInstaller - Download complete
[main] INFO p.a.t.e.ElasticSearchInstaller - Installing Elasticsearch into /var/folders/pl/l3n21...
[main] INFO p.a.t.e.ElasticSearchInstaller - Done
[main] INFO p.a.t.e.ElasticSearchInstaller - Applying executable permissions on /var/folders/pl/l3n21.../elasticsearch-6.2.4/bin/elasticsearch-plugin
[main] INFO p.a.t.e.ElasticSearchInstaller - Applying executable permissions on /var/folders/pl/l3n21.../elasticsearch-6.2.4/bin/elasticsearch
[main] INFO p.a.t.e.ElasticSearchInstaller - Applying executable permissions on /var/folders/pl/l3n21.../elasticsearch-6.2.4/bin/elasticsearch.in.sh
[main] INFO p.a.t.e.ElasticServer - Waiting for ElasticSearch to start...
[EmbeddedElsHandler] INFO p.a.t.e.ElasticServer - [2018-04-20T00:40:05,110][INFO ][o.e.n.Node               ] [] initializing ...
...

Comme vous pouvez le voir dans le journal, `ʻembedded-elasticsearch`` télécharge d'abord la version spécifiée du package de distribution ES à partir du serveur Elastic. Une fois le téléchargement terminé, décompressez-le dans un répertoire temporaire, définissez les attributs d'exécution du fichier, puis exécutez ES. Les packages de distribution ES téléchargés sont mis en cache dans le répertoire temporaire. Si le répertoire temporaire n'est pas nettoyé, le téléchargement sera ignoré à partir de la deuxième fois.

[main] INFO p.a.t.e.ElasticSearchInstaller - Download skipped
[main] INFO p.a.t.e.ElasticSearchInstaller - Installing Elasticsearch into /var/folders/pl/l3n21...
[main] INFO p.a.t.e.ElasticSearchInstaller - Done
...

Cependant, par défaut, le package de distribution ES est décompressé à chaque fois que la classe de test est exécutée, il est donc plus lent que «elasticsearch-cluster-runner».

Utilisation de plug-ins

Le plug-in à utiliser avec l'instance ES peut être spécifié par la méthode withPlugin (...) de `ʻEmbeddedElastic.Builder``.

  ...
  @BeforeAll
  public static void startES() throws Exception {

    es = EmbeddedElastic.builder()
      .withElasticVersion("6.2.4")
      .withPlugin("analysis-phonetic")
      .withPlugin("analysis-icu")
      .withSetting("discovery.zen.ping.unicast.hosts", Collections.emptyList())
      .build();
    ...

Si un plug-in est spécifié, le plug-in sera installé à l'aide de la commande `` bin / elasticserch-plugin '' avant de démarrer ES.

...
[main] INFO p.a.t.e.ElasticSearchInstaller - > /var/folders/pl/l3n21.../elasticsearch-6.2.4/bin/elasticsearch-plugin install analysis-phonetic
-> Downloading analysis-phonetic from elastic
[=================================================] 100%   
-> Installed analysis-phonetic
[main] INFO p.a.t.e.ElasticSearchInstaller - > /var/folders/pl/l3n21.../elasticsearch-6.2.4/bin/elasticsearch-plugin install analysis-icu
-> Downloading analysis-icu from elastic
[=================================================] 100%   
-> Installed analysis-icu
...

Le problème ici est que le package de distribution ES est mis en cache une fois téléchargé, tandis que le plug-in est téléchargé à chaque fois qu'il est testé. Il est très pénible de télécharger une grande prise comme la prise ICU pour chaque test, à part une petite prise comme la prise d'analyse phonétique.

Malheureusement, la bibliothèque «embarquée-elasticsearch» elle-même n'a actuellement pas de solution spécifique à ce problème. Cependant, puisque la méthode withPlugin (...) '' exécute également en interne bin / elasticserch-plugin '', l'argument de la méthode withPlugin (...) '' est le nom du plugin. Non seulement vous pouvez spécifier l'URL et le chemin du fichier local. Par conséquent, si vous souhaitez utiliser un plug-in pour tester, en réalité, vous devez implémenter votre propre mécanisme pour télécharger le package de plug-in et le mettre en cache localement avant de démarrer `ʻEmbedded Elastic.

Alors, quelle bibliothèque dois-je utiliser?

Cela dépend du type de client ES utilisé dans l'application. Le client Transport repose actuellement sur «elasticsearch-core» et de nombreux autres modules ES. Par conséquent, lorsque le module transport est ajouté à la dépendance, le contenu du chemin de classe ne sera pas très différent de celui de l'utilisation de elasticsearch-cluster-runner. Donc, dans ce cas, je pense que le démarrage rapide et hautement fonctionnel «elasticsearch-cluster-runner» est un bon choix.

D'un autre côté, si vous utilisez un client REST avec peu de dépendances et que vous ne voulez pas trop augmenter les dépendances, `ʻembedded-elasticsearch`` peut également être une bonne option.

Cependant, en écrivant cet article, j'ai réexaminé elasticsearch-cluster-runner, mais il est beaucoup plus sophistiqué, et Elasticsearch lui-même n'a pas tellement de dépendances que ce serait un problème si je le vérifiais à nouveau, donc Je me demande s'il y a moins de scènes où je devrais utiliser ʻembedded-elasticsearch``. Cette fois, je connais l'article "ʻembedded-elasticsearch``, mais j'aimerais écrire un article qui utilise ʻelasticsearch-cluster-runner``.

Recommended Posts

Test JUnit facile de la version Elasticsearch 2018 avec Embedded-elasticsearch
Faites un test unitaire avec Junit.
Erreur lors du démarrage de JUnit avec une version obsolète de POI
Tester le contenu d'un fichier Excel avec JUnit
Tester l'API Web avec junit
[Java] Tester des méthodes privées avec JUnit
Contrôleur de cadre de test Spring avec Junit
La version d'Elasticsearch que vous utilisez est-elle compatible avec Java 11?
Contrôler l'ordre de test dans Junit4 avec un type d'énumération
Comment tester l'étendue privée avec JUnit
Le test JUnit 5 Gradle génère une erreur avec l'annotation Lombok
Présentation du test Java automatisé avec JUnit 5 + Gradle
[Java] Comment tester s'il est nul dans JUnit
[CircleCI 2.0] [Java] [Maven] [JUnit] Agréger les résultats des tests JUnit avec CircleCI 2.0
Présentation des tests Java automatisés avec JUnit 5 + Apache Maven
Comment tester les interruptions pendant Thread.sleep avec JUnit
Gérez la version de Ruby elle-même avec rbenv
Écraser le contenu de la configuration avec Spring-boot + JUnit5
Tester le code à l'aide d'une maquette avec JUnit (centre EasyMock)
Mélanger les cas de test avec JUnit 5 et les méthodes par défaut
Jouons avec Minishift! Expérience facile de kubernetes
[JUnit 5] Traiter de "la référence d'assertEquals est ambiguë"
Obtenez le nom du scénario de test dans la classe de test JUnit
[Compatible JUnit 5] Ecrire un test en utilisant JUnit 5 avec Spring boot 2.2, 2.3
[JUnit 5] Ecrivez un test de validation avec Spring Boot! [Test de paramétrage]
Test unitaire de l'API Web et test d'intégration avec SpringBoot + Junit5, 4 modèles
J'ai écrit un test avec Spring Boot + JUnit 5 maintenant