Test de Netty avec EmbeddedChannel

Test de Netty avec EmbeddedChannel

1. introduction

Dans cet article, nous allons voir comment utiliserEmbeddedChannel pour tester les fonctionnalités de nos gestionnaires de canaux entrants et sortants.

Netty est un framework très polyvalent pour l'écriture d'applications asynchrones hautes performances. Le test unitaire de telles applications peut être délicat sans les bons outils.

Heureusement, le framework nous fournit lesEmbeddedChannel class – which facilitates the testing of ChannelHandlers.

2. Installer

LeEmbeddedChannel fait partie du framework Netty, donc la seule dépendance nécessaire est celle de Netty lui-même.

La dépendance peut être trouvée surMaven Central:


    io.netty
    netty-all
    4.1.24.Final

3. EmbeddedChannelOverview

LeEmbeddedChannelclass is just another implementation of AbstractChannel – qui transporte les donnéeswithout the need for a real network connection.

Ceci est utile car nous pouvons simuler des messages entrants en écrivant des données sur les canaux entrants et également vérifier la réponse générée sur les canaux sortants. De cette façon, nous pouvons tester individuellement chaqueChannelHandler or dans tout le pipeline de canal.

Pour tester un ou plusieursChannelHandlers, we doit d'abord créer une instanceEmbeddedChannel en utilisant l'un de ses constructeurs.

La manière la plus courante d'initialiser un sysEmbeddedChannel en passant la liste deChannelHandlers à son constructeur:

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

Si nous voulons avoir plus de contrôle sur l'ordre dans lequel les gestionnaires sont insérés dans le pipeline, nous pouvons créer unEmbeddedChannel avec le constructeur par défaut et ajouter directement les gestionnaires:

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

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

Lorsque nous voulons utiliser une configuration personnalisée, comme abaisser la valeur du délai de connexion par rapport à la valeur par défaut, nous pouvons accéder au sobjectChannelConfig en utilisant la méthodeconfig():

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

LeEmbeddedChannel in comprend des méthodes que nous pouvons utiliser pour lire et écrire des données dans nosChannelPipeline. Les méthodes les plus couramment utilisées sont:

  • readInbound ()

  • readOutbound ()

  • writeInbound (Objet… msgs)

  • writeOutbound (Objet… msgs)

The read methods retrieve and remove the first element in the inbound/outbound queue.Lorsque nous avons besoin d'accéder à toute la file d'attente de messages sans supprimer aucun élément, nous pouvons utiliser la méthodeoutboundMessages() :

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


Les méthodes d'écriture renvoienttrue lorsque le message a été ajouté avec succès au pipeline entrant / sortant desChannel:

channel.writeInbound(httpRequest)

L'idée est que nous écrivons des messages sur le pipeline entrant de sorte que le swill outChannelHandlersles traite et nous nous attendons à ce que le résultat soit lisible depuis le pipeline sortant.

4. Test deChannelHandlers

Prenons un exemple simple dans lequel nous voulons tester un pipeline composé de deuxChannelHandlers t qui reçoivent une requête HTTP et attendons une réponse HTTP contenant le résultat d'un calcul:

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

Le premier,HttpMessageHandler , extrait les données de la requête HTTP et les transmet aux secondesChannelHandler in le pipeline,CalculatorOperationHandler, pour effectuer le traitement des données.

Maintenant, écrivons la requête HTTP et voyons si le pipeline entrant la traite:

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

Nous pouvons voir que nous avons envoyé la requête HTTP sur le pipeline entrant en utilisant la méthodewriteInbound() et lu le résultat avecreadInbound(); inboundChannelResponse est le message résultant des données que nous avons envoyées après leur traitement par tous lesChannelHandlers in du pipeline entrant.

Maintenant, vérifions si notre serveur Netty répond avec le bon message de réponse HTTP. Pour ce faire, nous allons vérifier si un message existe sur le pipeline sortant:

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

Le message sortant, dans ce cas, est une réponse HTTP, donc vérifions si le contenu est correct. Nous faisons cela en lisant le dernier message du pipeline sortant:

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

4. Tester la gestion des exceptions

Un autre scénario de test courant est la gestion des exceptions.

Nous pouvons gérer les exceptions dans notreChannelInboundHandlers  en implémentant la méthodeexceptionCaught() , mais il y a des cas où nous ne voulons pas gérer une exception et à la place, nous la passons auChannelHandleruivant pipeline.

Nous pouvons utiliser la méthodecheckException() de la classeEmbeddedChannelpour vérifier si un sobjectThrowable a été reçu sur le pipeline et le relancer.

De cette façon, nous pouvons attraper le test de sableException i leChannelHandler aurait dû ou non le lancer:

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

Nous pouvons voir dans l'exemple ci-dessus, que nous avons envoyé une requête HTTP dont nous nous attendons à déclencher unException. En utilisant la méthodecheckException() , nous pouvons renvoyer la dernière exception qui existe dans le pipeline, afin que nous puissions affirmer ce dont nous avons besoin.

5. Conclusion

LeEmbeddedChannel  est une excellente fonctionnalité fournie par le framework Netty pour nous aider à tester l'exactitude de la spipeline outChannelHandler . Il peut être utilisé pour tester chaqueChannelHandler individuellement et surtout l'ensemble du pipeline.

Le code source de l'article est disponibleover on GitHub.