[JAVA] Einfacher JUnit-Test der Elasticsearch 2018-Version mit Embedded-Elasticsearch

Embedded Elasticsearch: Starten Sie ES im Testcode

Wie führen Sie Unit-Tests und Integrationstests von Anwendungen mit Elasticsearch durch? Ich denke, es gibt verschiedene Methoden wie das Erstellen und Einfügen eines ES-Client-Mocks, das Herstellen einer Verbindung zu einer extern ausgeführten ES-Instanz usw., aber es ist praktisch, die eingebettete elastische Suche nur für die Entwicklung von Java-Anwendungen zu verwenden. Die Methode existierte einmal. Mit anderen Worten, da ES selbst eine Java-Anwendung ist, ist es eine Methode, um ES Node zusammen auf der JVM zu starten, die den Test ausführt und als ES-Instanz zum Testen verwendet. Obwohl es sich um Testzwecke handelt, handelt es sich um eine echte ES-Instanz, die kein Schein ist. Daher war es sehr praktisch, dass sowohl die Indizierung als auch die Suche normal funktionierten. Elastic selbst bietet auch eine JUnit-Testvorlage mit dem Namen "ESIntegTestCase", und ich habe vor einigen Jahren einen Artikel geschrieben.

Seit Version 5 ist diese Verwendung der eingebetteten elastischen Suche jedoch immer schwieriger geworden.

Da das Unternehmen auch ein Testframework mit Embedded Elasticsearch im eigenen Haus erstellt und dieses gründlich verwendet hat, wurde beim Upgrade von ES2.x ein zum Testen erforderliches Modul zum internen Maven-Repository hinzugefügt, während mit einem Kollegen geflüstert wurde. Die komplizierte Arbeit, sich einzeln zu registrieren, wurde notwendig.

Es scheint, dass es andere Leute gab, die ähnliche Probleme hatten, und als ich die elastischen Foren überprüfte, wurden die folgenden Alternativen vorgeschlagen.

Kurz gesagt, es ist eine Möglichkeit, eine Test-ES-Instanz in Verbindung mit einem Build-Tool auszuführen. Dies kann damit verwendet werden, aber es ist einfach, Testfälle direkt auf der IDE auszuführen, ohne ein Build-Tool zu durchlaufen, und es ist einfach, die Einstellung und den Start von ES-Knoten direkt über den Testcode usw. zu steuern. Embedded Elasticsearch Viele der Vorteile von gehen verloren.

Daher wurden auch nach ES 5.x einige Bibliotheken entwickelt, die so etwas wie eine eingebettete elastische Suche realisieren.

Elasticsearch-Cluster-Runner ist eine Bibliothek zur Verwendung von Embedded Elasticsearch auch nach ES5.x. ES-Module, die nicht in Maven Central hochgeladen wurden, wurden selbst in Maven Central hochgeladen. Mein Kopf geht runter.

embedded-elasticsearch ist ein etwas anderer Ansatz. Im Gegensatz zum Namen "Embedded-Elasticsearch" wird in dieser Bibliothek ES nicht auf derselben JVM wie der Test ausgeführt. Führen Sie stattdessen die ES-Instanz als externen Prozess mit den folgenden Schritten für jeden Test aus.

Mit anderen Worten, Sie erhalten dieselbe Umgebung, in der Sie normalerweise eine ES herunterladen und ausführen würden. Andererseits ähnelt die Benutzerfreundlichkeit, mit der die ES-Knotensteuerung über den Testcode programmiert werden kann, der Suche nach eingebetteten elastischen Elementen.

Jeder hat seine Vor- und Nachteile

Embedded Elasticsearch muss ES auch auf derselben JVM starten, damit alle zum Ausführen von ES erforderlichen Abhängigkeiten zum Klassenpfad hinzugefügt werden. Infolgedessen kann es zu Konflikten mit den Abhängigkeiten der Anwendung kommen, die Sie ursprünglich testen möchten. Andererseits verursacht "Embedded-Elasticsearch" nicht das gleiche Problem, da ES als externer Prozess ausgeführt wird. Die "Embedded-Elasticsearch" selbst ist ebenfalls sehr leicht und stützt sich ausschließlich auf Jackson und einige Commons-Bibliotheken.

Der vordere Mund ist lang geworden, aber in diesem Artikel werde ich versuchen, "Embedded-Elasticsearch" von JUnit zu verwenden.

Grundlegende Verwendung von embedded-elasticsearch

Abhängigkeitseinstellung

Fügen Sie der Abhängigkeit pl.allegro.tech: embedded-elasticsearch hinzu. Die neueste Version ist 2.5.0. Die neueste Version wird empfohlen, da das Problem unter Windows kürzlich behoben wurde.

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-elasticsearch verwendet SLF4J für die Protokollierung, enthält jedoch nur slf4j-api als Abhängigkeit. Wenn also keine geeignete Bindung für die Abhängigkeit vorhanden ist, fügen Sie diese ebenfalls hinzu (Beispiel oben). Dann slf4j-simple). In diesem Beispiel wird JUnit5 als Testframework verwendet, aber natürlich kann es problemlos mit JUnit4 und ScalaTest verwendet werden.

Testcode

Der Testcode sieht so aus.

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();
  }

}

Erstellen Sie mit dem Builder eine Instanz von "EmbeddedElastic", bevor Sie alle Tests ausführen ("@ BeforeAll"). Sie können die ES-Version angeben und über den Builder festlegen (schließlich in config / elasticsearch.yml geschrieben). Die mit (*) gekennzeichneten Einstellungen sind Problemumgehungen, die die Zen-Erkennung für ES deaktivieren. Wenn ES auf demselben Computer ausgeführt wird, kann der zum Testen gestartete ES-Knoten ohne diese Einstellung versehentlich eine Verbindung herstellen.

ES wird durch Aufrufen von EmbeddedElastic # start () gestartet. Die Portnummer für die Verbindung mit dem gestarteten ES erhalten Sie, indem Sie getHttpPort () oder getTransportTcpPort () aufrufen. Ich denke, dass Sie im eigentlichen Test einen Client erstellen oder einen Dienst zum Testen unter Verwendung dieser Portnummern festlegen werden.

Sie müssen daran denken, "EmbeddedElastic # stop ()" aufzurufen, um die ES zu stoppen, nachdem alle Tests abgeschlossen sind ("@ AfterAll").

Grundbetrieb

Wenn der obige Test ausgeführt wird, wird das folgende Protokoll ausgegeben.

[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 ...
...

Wie Sie im Protokoll sehen können, lädt embedded-elasticsearch zuerst die angegebene Version des ES-Distributionspakets vom elastischen Server herunter. Wenn der Download abgeschlossen ist, entpacken Sie ihn in ein temporäres Verzeichnis, legen Sie die Ausführungsattribute der Datei fest und führen Sie dann ES aus. Heruntergeladene ES-Distributionspakete werden im temporären Verzeichnis zwischengespeichert. Wenn das temporäre Verzeichnis nicht bereinigt wird, wird der Download ab dem zweiten Mal übersprungen.

[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
...

Standardmäßig wird das ES-Verteilungspaket jedoch bei jeder Ausführung der Testklasse dekomprimiert, sodass es langsamer als "Elasticsearch-Cluster-Runner" ist.

Verwendung von Plug-Ins

Das mit der ES-Instanz zu verwendende Plug-In kann mit der Methode withPlugin (...) von EmbeddedElastic.Builder angegeben werden.

  ...
  @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();
    ...

Wenn ein Plug-In angegeben ist, wird das Plug-In vor dem Starten von ES mit dem Befehl bin / elasticserch-plugin installiert.

...
[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
...

Das Problem hierbei ist, dass das ES-Distributionspaket nach dem Herunterladen zwischengespeichert wird, während das Plug-In bei jedem Test heruntergeladen wird. Es ist sehr schmerzhaft, für jeden Test einen großen Stecker wie den ICU-Stecker herunterzuladen, abgesehen von einem kleinen Stecker wie dem phonetischen Analyse-Stecker.

Leider hat die Bibliothek "Embedded-Elasticsearch" selbst derzeit keine spezifische Lösung für dieses Problem. Da die withPlugin (...) -Methode bin / elasticserch-plugin auch intern ausführt, ist das Argument der withPlugin (...) -Methode der Plugin-Name. Sie können nicht nur die URL und den Pfad der lokalen Datei angeben. Wenn Sie ein Plug-In zum Testen verwenden möchten, müssen Sie in der Realität einen Mechanismus implementieren, um das Plug-In-Paket herunterzuladen und lokal zwischenzuspeichern, bevor Sie "Embedded Elastic" starten.

Welche Bibliothek soll ich also verwenden?

Dies hängt vom Typ des in der Anwendung verwendeten ES-Clients ab. Der Transport-Client stützt sich derzeit auf "Elasticsearch-Core" und viele andere ES-Module. Wenn das Modul "Transport" zur Abhängigkeit hinzugefügt wird, unterscheidet sich der Inhalt des Klassenpfads daher nicht wesentlich von dem bei Verwendung von "Elasticsearch-Cluster-Runner". In diesem Fall denke ich, dass "Elasticsearch-Cluster-Runner", das schnell startet und eine hohe Funktionalität aufweist, eine gute Wahl ist.

Wenn Sie jedoch einen REST-Client mit weniger Abhängigkeiten verwenden und die Abhängigkeiten nicht zu stark erhöhen möchten, kann "Embedded-Elasticsearch" ebenfalls eine gute Option sein.

Beim Schreiben dieses Artikels habe ich jedoch "Elasticsearch-Cluster-Runner" erneut untersucht, aber es ist viel ausgefeilter, und Elasticsearch selbst weist nicht so viele Abhängigkeiten auf, dass es ein Problem wäre, wenn ich es erneut überprüfe Ich werde daran erinnert, dass es weniger Szenen gibt, in denen ich "Embedded-Elasticsearch" verwenden sollte. Dieses Mal bin ich mit dem Artikel "Embedded-Elasticsearch" vertraut, aber ich möchte einen Artikel schreiben, der den "Elasticsearch-Cluster-Runner" verwendet.

Recommended Posts

Einfacher JUnit-Test der Elasticsearch 2018-Version mit Embedded-Elasticsearch
Machen Sie einen Unit-Test mit Junit.
Fehler beim Starten von JUnit mit veralteter POI-Version
Testen Sie den Inhalt einer Excel-Datei mit JUnit
Testen Sie die Web-API mit junit
[Java] Testen Sie private Methoden mit JUnit
Testen Sie den Spring Framework Controller mit Junit
Ist die von Ihnen verwendete Version von Elasticsearch mit Java 11 kompatibel?
Steuern Sie die Testreihenfolge in Junit4 mit einem Aufzählungstyp
So testen Sie den privaten Bereich mit JUnit
Der JUnit 5-Gradle-Test führt zu einem Fehler mit der Lombok-Annotation
Einführung eines automatisierten Java-Tests mit JUnit 5 + Gradle
[Java] So testen Sie, ob es in JUnit null ist
[CircleCI 2.0] [Java] [Maven] [JUnit] Aggregieren Sie die JUnit-Testergebnisse mit CircleCI 2.0
Einführung automatisierter Java-Tests mit JUnit 5 + Apache Maven
So testen Sie Interrupts während Thread.sleep mit JUnit
Verwalten Sie die Version von Ruby selbst mit rbenv
Überschreiben Sie den Inhalt der Konfiguration mit Spring-boot + JUnit5
Testcode mit Mock mit JUnit (EasyMock Center)
Mischen Sie Testfälle mit JUnit 5 und Standardmethoden
Lass uns mit Minishift spielen! Einfache Erfahrung von Kubernetes
[JUnit 5] Der Umgang mit "der Referenz von assertEquals ist mehrdeutig"
Rufen Sie den Namen des Testfalls in der JUnit-Testklasse ab
[JUnit 5-kompatibel] Schreiben Sie einen Test mit JUnit 5 mit Spring Boot 2.2, 2.3
[JUnit 5] Schreiben Sie einen Validierungstest mit Spring Boot! [Parametrisierungstest]
Web-API-Komponententest und Integrationstest mit SpringBoot + Junit5, 4 Muster
Ich habe jetzt einen Test mit Spring Boot + JUnit 5 geschrieben