Java >> Java tutorial >  >> Tag >> Netty

Tester Netty med EmbeddedChannel

1. Introduktion

I denne artikel kan vi se, hvordan du bruger EmbeddedChannel  for at teste funktionaliteten af ​​vores indgående og udgående kanalhandlere.

Netty er en meget alsidig ramme til at skrive højtydende asynkrone applikationer. Enhedstest af sådanne applikationer kan være vanskelig uden de rigtige værktøjer.

Heldigvis giver rammen os den EmbeddedChannel  klasse – som letter testningen af ChannelHandlers .

2. Opsætning

Den Embedded Channel er en del af Netty-rammen, så den eneste nødvendige afhængighed er den til Netty selv.

Afhængigheden kan findes på Maven Central:

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

3. Indlejret kanal Oversigt

Den Embedded Channel klasse er blot endnu en implementering af AbstractChannel  – som transporterer data uden behov for en rigtig netværksforbindelse .

Dette er nyttigt, fordi vi kan simulere indgående beskeder ved at skrive data på de indgående kanaler og også kontrollere det genererede svar på de udgående kanaler. På denne måde kan vi teste hver ChannelHandler  individuelt eller i hele kanalpipelinen.

For at teste en eller flere ChannelHandlers ,  vi skal først oprette en EmbeddedChannel  instans ved hjælp af en af ​​dens konstruktører.

Den mest almindelige måde at initialisere en EmbeddedChannel  er ved at videregive listen over ChannelHandlers  til sin konstruktør:

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

Hvis vi ønsker at have mere kontrol over den ordre, som behandlerne indsættes i pipelinen, kan vi oprette en EmbeddedChannel med standardkonstruktøren og tilføj handlerne direkte:

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

Også når vi opretter en Embedded Channel det vil have en standardkonfiguration givet af DefaultChannelConfig klasse.

Når vi vil bruge en tilpasset konfiguration, som at sænke timeoutværdien for forbindelsen fra standardværdien, kan vi få adgang til ChannelConfig  objekt ved at bruge config() metode:

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

Den EmbeddedChannel  omfatter metoder, som vi kan bruge til at læse og skrive data til vores ChannelPipeline . De mest brugte metoder er:

  • readInbound()
  • readOutbound()
  • writeInbound(Object… msgs)
  • writeOutbound(Object… msgs)

Læsemetoderne henter og fjerner det første element i den indgående/udgående kø. Når vi har brug for adgang til hele køen af ​​beskeder uden at fjerne noget element, kan vi bruge outboundMessages()  metode:

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

Skrivemetoderne returnerer true  når meddelelsen blev tilføjet til den indgående/udgående pipeline på Kanalen:

channel.writeInbound(httpRequest)

Tanken er, at vi skriver beskeder på den indgående pipeline, så de ude ChannelHandlers behandler dem, og vi forventer, at resultatet kan læses fra den udgående pipeline.

4. Test af ChannelHandlers

Lad os se på et simpelt eksempel, hvor vi vil teste en pipeline sammensat af to ChannelHandlers  der modtager en HTTP-anmodning og forventer et HTTP-svar, der indeholder resultatet af en beregning:

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

Den første, HttpMessageHandler  vil udtrække dataene fra HTTP-anmodningen og videregive dem til sekunders ChannelHandler  i pipelinen, CalculatorOperationHandler , for at behandle dataene.

Lad os nu skrive HTTP-anmodningen og se, om den indgående pipeline behandler den:

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

Vi kan se, at vi har sendt HTTP-anmodningen på den indgående pipeline ved hjælp af writeInbound()  metode og læs resultatet med readInbound(); inboundChannelResponse  er den besked, der stammer fra de data, vi har sendt, efter at de blev behandlet af alle ChannelHandlers  i den indgående pipeline.

Lad os nu tjekke, om vores Netty-server svarer med den korrekte HTTP-svarmeddelelse. For at gøre dette kontrollerer vi, om der findes en meddelelse på den udgående pipeline:

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

Den udgående meddelelse er i dette tilfælde et HTTP-svar, så lad os tjekke, om indholdet er korrekt. Det gør vi ved at læse den sidste besked i den udgående pipeline:

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

4. Test af undtagelseshåndtering

Et andet almindeligt testscenarie er undtagelseshåndtering.

Vi kan håndtere undtagelser i vores ChannelInboundHandlers  ved at implementere exceptionCaught()  metode, men der er nogle tilfælde, hvor vi ikke ønsker at håndtere en undtagelse, og i stedet sender vi den videre til den næste ChannelHandler i pipelinen.

Vi kan bruge checkException()  metode fra EmbeddedChannel klasse for at kontrollere, om nogen kan kastes  objekt blev modtaget på rørledningen og kaster det igen.

På denne måde kan vi fange undtagelsen  og kontroller, om ChannelHandler burde eller burde ikke have smidt det:

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

Vi kan se i eksemplet ovenfor, at vi har sendt en HTTP-anmodning, som vi forventer vil udløse en undtagelse . Ved at bruge checkException()  metode, kan vi omkaste den sidste undtagelse, der eksisterer i pipelinen, så vi kan hævde, hvad der er nødvendigt fra det.

5. Konklusion

Den EmbeddedChannel  er en fantastisk funktion leveret af Netty-rammen for at hjælpe os med at teste rigtigheden af ​​ChannelHandler  rørledning. Den kan bruges til at teste hver ChannelHandler  individuelt og endnu vigtigere hele pipelinen.

Kildekoden til artiklen er tilgængelig på GitHub.


Java tag