14

I implement a handler which extends SimpleChannelHandler, and overrides some methods such as channelConnected, messageReceived. However, I am wondering how to unit test it?

I searched about "netty unit test" and found one article which said considering CodecEmbedder, but I am still not sure how to begin. Do you have any example or advice on how to unit test Netty code?

Thanks a lot.

zhquake
  • 296
  • 2
  • 9

1 Answers1

19

In Netty, there are different ways to test your networking stack.

Testing ChannelHandlers

You can use Netty's EmbeddedChannel to mock a netty connection for testing, an example of this would be:

@Test
public void nettyTest() {
    EmbeddedChannel channel = new EmbeddedChannel(new StringDecoder(StandardCharsets.UTF_8));
    channel.writeInbound(Unpooled.wrappedBuffer(new byte[]{(byte)0xE2,(byte)0x98,(byte)0xA2}));
    String myObject = channel.readInbound();
    // Perform checks on your object
    assertEquals("☢", myObject);
}

This test above tests for StringDecoder ability to decode unicode correct (example from this bug posted by me)

You can also test the encoder direction using EmbeddedChannel, for this you should use writeOutBound and readInbound.

More Examples:

DelimiterBasedFrameDecoderTest.java:

@Test
public void testIncompleteLinesStrippedDelimiters() {
    EmbeddedChannel ch = new EmbeddedChannel(new DelimiterBasedFrameDecoder(8192, true,
            Delimiters.lineDelimiter()));
    ch.writeInbound(Unpooled.copiedBuffer("Test", Charset.defaultCharset()));
    assertNull(ch.readInbound());
    ch.writeInbound(Unpooled.copiedBuffer("Line\r\ng\r\n", Charset.defaultCharset()));
    assertEquals("TestLine", releaseLater((ByteBuf) ch.readInbound()).toString(Charset.defaultCharset()));
    assertEquals("g", releaseLater((ByteBuf) ch.readInbound()).toString(Charset.defaultCharset()));
    assertNull(ch.readInbound());
    ch.finish();
}

More examples on github.

ByteBuf

To test if you use your bytebufs, you can set a JVM parameter that checks for leaked ByteBuf, for this, you should add -Dio.netty.leakDetectionLevel=PARANOID to the startup parameters, or call the method ResourceLeakDetector.setLevel(PARANOID).

Ferrybig
  • 18,194
  • 6
  • 57
  • 79
  • It took me a little time until I understood it, but I made it work. I simply replaced the parameter in the constructor for EmbeddedChannel with my ChannelHandler. Did you find a way no to repeat so much code? I mean... channel = new EmbeddedChannel(new MessageHandler1()); channel = new EmbeddedChannel(new MessageHandler2()); etc... – Sebastian D'Agostino Feb 18 '16 at 17:52
  • Thanks! I have been using Netty a while and never knew how to test me handler logic other then settings up a server! This will save me so much time!!!!!!!!!! – Mr00Anderson Oct 08 '16 at 14:32
  • 1
    @Ferrybig The tests you showed and some of the examples on the github link make sense in that you are testing a specific network protocol or a certain rule. What about handlers that do some other business logic action. Like if I have an AuthHandler that has an authService that validates the user. I have UT for authService, but essentially channelReadComplete just calls authService.validate(user). Are those scenarios that are testable still? – Crystal Jul 25 '17 at 22:31
  • How do you suggest we pass or fail a test when using `ResourceLeakDetector.setLevel(PARANOID)`? – Dave Moten Mar 14 '18 at 00:07
  • @Ferrybig Helped me big time. Thanks!! – Srini Mar 19 '19 at 09:52