EmbeddedChannelを使ってNettyをテストする

1.はじめに

この記事では、 __EmbeddedChannel __を使用して、インバウンドおよびアウトバウンドのチャネルハンドラの機能をテストする方法について説明します。

Netty は高性能の非同期アプリケーションを書くための非常に用途の広いフレームワークです。このようなアプリケーションの単体テストは、適切なツールがないと難しい場合があります。

ありがたいことに、フレームワークは _ EmbeddedChannel classを提供しています - これは ChannelHandlers_ のテストを容易にします。

2.セットアップ

__EmbeddedChannel __はNettyフレームワークの一部なので、必要な唯一の依存関係はNetty自体の依存関係です。

依存はhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22io.netty%22%20AND%20a%3A%22netty-all%22[Maven Centralで見つけることができます]:

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.24.Final</version>
</dependency>

3. __ EmbeddedChannel __概要

  • _ EmbeddedChannel クラスは AbstractChannel _ ** のもう1つの実装です - 実際のネットワーク接続を必要とせずにデータを転送します。

これは、インバウンドチャネルにデータを書き込むことでインバウンドメッセージをシミュレートし、アウトバウンドチャネルで生成された応答を確認することができるので便利です。これにより、チャネルパイプライン全体で各____ChannelHandlerを個別にテストできます。

1つ以上の ChannelHandler をテストするには、まず、コンストラクタの1つを使用して____EmbeddedChannelインスタンスを作成する必要があります。

__ChannelHandlersのリストをコンストラクタに渡すことで __EmbeddedChannelを初期化する最も一般的な方法は次のとおりです。

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

ハンドラがパイプラインに挿入される順序をもっと制御したい場合は、デフォルトのコンストラクタで EmbeddedChannel を作成し、ハンドラを直接追加します。

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

また、** EmbeddedChannelを作成すると、 DefaultChannelConfig __クラスで指定されたデフォルト設定が使用されます。

デフォルトから接続タイムアウト値を減らすなど、カスタム設定を使用したい場合は、 __ config() メソッドを使用して ChannelConfig __objectにアクセスできます。

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

__EmbeddedChannel には、 ChannelPipeline__へのデータの読み書きに使用できるメソッドが含まれています。最も一般的に使用されている方法は次のとおりです。

  • readInbound()

  • readOutbound()

  • writeInbound(Object …​ msgs)

  • writeOutbound(Object …​ msgs)

  • readメソッドは、インバウンド/アウトバウンドキューの最初の要素を取得して削除します。 ** 要素を削除せずにメッセージのキュー全体にアクセスする必要がある場合は、 __ outboundMessages() __methodを使用できます。

Object lastOutboundMessage = channel.readOutbound();
Queue<Object> allOutboundMessages = channel.outboundMessages();
  • Channelのインバウンド/アウトバウンドパイプラインへのメッセージの追加が成功した場合、writeメソッドは __trueを返します

channel.writeInbound(httpRequest)

その考えは、out __ChannelHandlers __がそれらを処理するようにインバウンドパイプライン上にメッセージを書くということであり、アウトバウンドパイプラインから結果が読めることを期待しています。

4. ChannelHandlers をテストする

HTTPリクエストを受け取り、計算結果を含むHTTPレスポンスを期待する2つの____ChannelHandlerで構成されるパイプラインをテストする簡単な例を見てみましょう。

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

最初のメソッド __HttpMessageHandlerはHTTPリクエストからデータを抽出し、それをパイプラインの秒 ChannelHandler CalculatorOperationHandler に渡して、データを処理します。

それでは、HTTPリクエストを書き、インバウンドパイプラインがそれを処理するかどうかを確認しましょう。

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

__writeInbound() メソッドを使用してインバウンドパイプラインでHTTPリクエストを送信し、その結果を readInbound() で読み取ったことがわかります。 inboundChannelResponseは、インバウンドパイプライン内のすべての __ChannelHandlerによって処理された後に送信されたデータに起因するメッセージです。

それでは、Nettyサーバーが正しいHTTP応答メッセージで応答するかどうかを確認しましょう。これを行うには、アウトバウンドパイプラインにメッセージが存在するかどうかを確認します。

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

この場合、送信メッセージはHTTP応答です。内容が正しいかどうかを確認しましょう。これを行うには、アウトバウンドパイプラインの最後のメッセージを読みます。

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

4.例外処理のテスト

別の一般的なテストシナリオは例外処理です。

__ChannelInboundHandlersで exceptionCaught()メソッドを実装することで例外を処理できますが、例外を処理したくない場合があり、代わりにパイプラインの次の ChannelHandler __に渡します。

パイプラインで __Throwable objectが受信されたかどうかを確認し、それを再スローするために EmbeddedChannel クラスの checkException() __メソッドを使用できます。

このようにして __Exception をキャッチし、 ChannelHandler __がそれをスローすべきでないかどうかをチェックすることができます。

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

上記の例では、 Exception が発生すると予想されるHTTPリクエストが送信されたことがわかります。 __checkException() __methodを使用することで、パイプラインに存在する最後の例外を再スローできます。そのため、そこから必要なものをアサートできます。

5.まとめ

__EmbeddedChannelは、Nettyフレームワークによって提供されている ChannelHandler pipelineの正しさをテストするのに役立つ優れた機能です。これは各 __ChannelHandlerを個別にそしてより重要なことにはパイプライン全体をテストするために使用することができます。

この記事のソースコードはhttps://github.com/eugenp/tutorials/tree/master/libraries-server[GitHubで利用可能]です。