Testen von Netty mit EmbeddedChannel

Testen von Netty mit EmbeddedChannel

1. Einführung

In diesem Artikel erfahren Sie, wie Sie mitEmbeddedChannel die Funktionalität unserer Handler für eingehende und ausgehende Kanäle testen.

Netty ist ein sehr vielseitiges Framework zum Schreiben von asynchronen Hochleistungsanwendungen. Der Unit-Test solcher Anwendungen kann ohne die richtigen Tools schwierig sein.

Zum Glück liefert uns das Framework dieEmbeddedChannel class – which facilitates the testing of ChannelHandlers.

2. Konfiguration

DerEmbeddedChannelis-Teil des Netty-Frameworks, daher ist nur die Abhängigkeit für Netty selbst erforderlich.

Die Abhängigkeit kann überMaven Central gefunden werden:


    io.netty
    netty-all
    4.1.24.Final

3. EmbeddedChannelOverview

EmbeddedChannelclass is just another implementation of AbstractChannel –, das Datenwithout the need for a real network connection transportiert.

Dies ist nützlich, da wir eingehende Nachrichten simulieren können, indem wir Daten auf die eingehenden Kanäle schreiben und auch die generierte Antwort auf die ausgehenden Kanäle überprüfen. Auf diese Weise können wir jedenChannelHandler or in der gesamten Kanalpipeline einzeln testen.

Um ein oder mehrereChannelHandlers zu testen, muss we zuerst mit einem seiner Konstruktoren eineEmbeddedChannel -Sinstanz erstellen.

Die gebräuchlichste Methode zum Initialisieren einerEmbeddedChannel -Sis durch Übergeben der Liste vonChannelHandlers an den Konstruktor:

EmbeddedChannel channel = new EmbeddedChannel(
  new HttpMessageHandler(), new CalculatorOperationHandler());

Wenn wir mehr Kontrolle über die Reihenfolge haben möchten, in der die Handler in die Pipeline eingefügt werden, können wir mit dem Standardkonstruktor einEmbeddedChannel erstellen und die Handler direkt hinzufügen:

channel.pipeline()
  .addFirst(new HttpMessageHandler())
  .addLast(new CalculatorOperationHandler());

Auchwhen we create an EmbeddedChannel, it’ll have a default configuration given by the DefaultChannelConfigclass.

Wenn wir eine benutzerdefinierte Konfiguration verwenden möchten, z. B. den Wert für das Verbindungszeitlimit von der Standardkonfiguration verringern möchten, können wir mithilfe der Methodeconfig()auf das ObjektChannelConfig zugreifen:

DefaultChannelConfig channelConfig = (DefaultChannelConfig) channel
  .config();
channelConfig.setConnectTimeoutMillis(500);

DasEmbeddedChannel enthält Methoden, mit denen wir Daten in unsereChannelPipeline lesen und schreiben können. Die am häufigsten verwendeten Methoden sind:

  • readInbound ()

  • readOutbound ()

  • writeInbound (Object… msgs)

  • writeOutbound (Object… msgs)

The read methods retrieve and remove the first element in the inbound/outbound queue.Wenn wir Zugriff auf die gesamte Nachrichtenwarteschlange benötigen, ohne ein Element zu entfernen, können wir die MethodeoutboundMessages() verwenden:

Object lastOutboundMessage = channel.readOutbound();
Queue allOutboundMessages = channel.outboundMessages();


Die Schreibmethoden gebentrue zurück, wenn die Nachricht erfolgreich zur eingehenden / ausgehenden Pipeline derChannel: hinzugefügt wurde

channel.writeInbound(httpRequest)

Die Idee ist, dass wir Nachrichten in die eingehende Pipeline schreiben, damit sie von outChannelHandlersverarbeitet werden, und wir erwarten, dass das Ergebnis aus der ausgehenden Pipeline lesbar ist.

4. Testen vonChannelHandlers

Schauen wir uns ein einfaches Beispiel an, in dem wir eine Pipeline testen möchten, die aus zweiChannelHandlers besteht, die eine HTTP-Anforderung erhalten, und eine HTTP-Antwort erwarten, die das Ergebnis einer Berechnung enthält:

EmbeddedChannel channel = new EmbeddedChannel(
  new HttpMessageHandler(), new CalculatorOperationHandler());

Der erste,HttpMessageHandler will extrahiert die Daten aus der HTTP-Anforderung und übergibt sie an die SekundenChannelHandler in der PipelineCalculatorOperationHandler, um die Verarbeitung mit den Daten durchzuführen.

Schreiben wir nun die HTTP-Anforderung und prüfen, ob die eingehende Pipeline sie verarbeitet:

FullHttpRequest httpRequest = new DefaultFullHttpRequest(
  HttpVersion.HTTP_1_1, HttpMethod.GET, "/calculate?a=10&b=5");
httpRequest.headers().add("Operator", "Add");

assertThat(channel.writeInbound(httpRequest)).isTrue();
long inboundChannelResponse = channel.readInbound();
assertThat(inboundChannelResponse).isEqualTo(15);

Wir können sehen, dass wir die HTTP-Anforderung in der eingehenden Pipeline mit der MethodewriteInbound() gesendet und das Ergebnis mitreadInbound() gelesen haben. inboundChannelResponse ist die Nachricht, die sich aus den Daten ergibt, die wir gesendet haben, nachdem sie von allenChannelHandlers in der eingehenden Pipeline verarbeitet wurden.

Überprüfen wir nun, ob unser Netty-Server mit der richtigen HTTP-Antwortnachricht antwortet. Dazu prüfen wir, ob in der ausgehenden Pipeline eine Nachricht vorhanden ist:

assertThat(channel.outboundMessages().size()).isEqualTo(1);

In diesem Fall handelt es sich bei der ausgehenden Nachricht um eine HTTP-Antwort. Überprüfen Sie daher, ob der Inhalt korrekt ist. Wir tun dies, indem wir die letzte Nachricht in der ausgehenden Pipeline lesen:

FullHttpResponse httpResponse = channel.readOutbound();
String httpResponseContent = httpResponse.content()
  .toString(Charset.defaultCharset());
assertThat(httpResponseContent).isEqualTo("15");

4. Testen der Ausnahmebehandlung

Ein weiteres häufiges Testszenario ist die Ausnahmebehandlung.

Wir können Ausnahmen in unseremChannelInboundHandlers  behandeln, indem wir dieexceptionCaught() -Smethod implementieren, aber es gibt einige Fälle, in denen wir eine Ausnahme nicht behandeln möchten und sie stattdessen an das nächsteChannelHandlerin the übergeben Pipeline.

Wir können diecheckException() -Smethod aus derEmbeddedChannel-Skala verwenden, um zu überprüfen, ob einThrowable -Objekt in der Pipeline empfangen wurde, und es erneut zu werfen.

Auf diese Weise können wir denException -Sand abfangen und prüfen, obChannelHandlerihn hätte werfen sollen oder nicht:

assertThatThrownBy(() -> {
    channel.pipeline().fireChannelRead(wrongHttpRequest);
    channel.checkException();
}).isInstanceOf(UnsupportedOperationException.class)
  .hasMessage("HTTP method not supported");

Im obigen Beispiel sehen wir, dass wir eine HTTP-Anfrage gesendet haben, von der wir erwarten, dass sieException auslöst. Mit dercheckException() -Smethod können wir die letzte in der Pipeline vorhandene Ausnahme erneut auslösen, um zu bestätigen, was daraus benötigt wird.

5. Fazit

EmbeddedChannel ist eine großartige Funktion des Netty-Frameworks, mit der wir die Richtigkeit unsererChannelHandler -Spipeline testen können. Es kann verwendet werden, um jedesChannelHandler einzeln und vor allem die gesamte Pipeline zu testen.

Der Quellcode für den Artikel istover on GitHub verfügbar.