Netty: Testing encoders/decoders
I’ve been working with Netty a bit recently and having built a pipeline of encoders/decoders as described in this excellent tutorial wanted to test that the encoders and decoders were working without having to send real messages around.
Luckily there is a EmbeddedChannel which makes our life very easy indeed.
Let’s say we’ve got a message 'Foo' that we want to send across the wire. It only contains a single integer value so we’ll just send that and reconstruct 'Foo' on the other side.
We might write the following encoder to do this:
// Examples uses Netty 4.0.28.Final
public static class MessageEncoder extends MessageToMessageEncoder<Foo>
{
@Override
protected void encode( ChannelHandlerContext ctx, Foo msg, List<Object> out ) throws Exception
{
ByteBuf buf = ctx.alloc().buffer();
buf.writeInt( msg.value() );
out.add( buf );
}
}
public static class Foo
{
private Integer value;
public Foo(Integer value)
{
this.value = value;
}
public int value()
{
return value;
}
}
So all we’re doing is taking the 'value' field out of 'Foo' and putting it into the list which gets passed downstream.
Let’s write a test which simulates sending a 'Foo' message and has an empty decoder attempt to process the message:
@Test
public void shouldEncodeAndDecodeVoteRequest()
{
// given
EmbeddedChannel channel = new EmbeddedChannel( new MessageEncoder(), new MessageDecoder() );
// when
Foo foo = new Foo( 42 );
channel.writeOutbound( foo );
channel.writeInbound( channel.readOutbound() );
// then
Foo returnedFoo = (Foo) channel.readInbound();
assertNotNull(returnedFoo);
assertEquals( foo.value(), returnedFoo.value() );
}
public static class MessageDecoder extends MessageToMessageDecoder<ByteBuf>
{
@Override
protected void decode( ChannelHandlerContext ctx, ByteBuf msg, List<Object> out ) throws Exception { }
}
So in the test we write 'Foo' to the outbound channel and then read it back into the inbound channel and then check what we’ve got. If we run that test now this is what we’ll see:
junit.framework.AssertionFailedError
at NettyTest.shouldEncodeAndDecodeVoteRequest(NettyTest.java:28)
The message we get back is null which makes sense given that we didn’t bother writing the decoder. Let’s implement the decoder then:
public static class MessageDecoder extends MessageToMessageDecoder<ByteBuf>
{
@Override
protected void decode( ChannelHandlerContext ctx, ByteBuf msg, List<Object> out ) throws Exception
{
int value = msg.readInt();
out.add( new Foo(value) );
}
}
Now if we run our test again it’s all green and happy. We can now go and encode/decode some more complex structures and update our test accordingly.
About the author
I'm currently working on short form content at ClickHouse. I publish short 5 minute videos showing how to solve data problems on YouTube @LearnDataWithMark. I previously worked on graph analytics at Neo4j, where I also co-authored the O'Reilly Graph Algorithms Book with Amy Hodler.