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.
bin / elasticsearch
aus, um eine ES-Instanz zu startenMit 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
Elasticsearch-Cluster-Runner
: ** Schnellerer Start ** ・ Höhere Funktionalität ・ Standardmäßig Start mit mehreren Knoten embedded-elasticsearch
: ** Sehr wenige Abhängigkeiten **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.
embedded-elasticsearch
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.
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").
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.
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.
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