Статьи

Netty: тестирование кодеров / декодеров

Недавно я работал с Netty и создал конвейер кодеров / декодеров, как описано в этом превосходном руководстве, и хотел проверить, работают ли кодеры и декодеры без необходимости отправлять реальные сообщения.

К счастью, есть встроенный канал, который действительно облегчает нашу жизнь.

Допустим, у нас есть сообщение «Foo», которое мы хотим отправить по сети. Он содержит только одно целочисленное значение, поэтому мы просто отправим его и восстановим ‘Foo’ с другой стороны.

Мы могли бы написать следующий кодер для этого:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 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;
    }
}

Таким образом, все, что мы делаем, это извлекаем поле ‘value’ из ‘Foo’ и помещаем его в список, который передается вниз по течению.

Давайте напишем тест, который имитирует отправку сообщения «Foo» и имеет пустую попытку декодера обработать сообщение:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
@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 { }
}

Итак, в тесте мы пишем ‘Foo’ в исходящий канал, а затем читаем его обратно во входящий канал и затем проверяем, что у нас есть. Если мы запустим этот тест сейчас, вот что мы увидим:

1
2
junit.framework.AssertionFailedError
    at NettyTest.shouldEncodeAndDecodeVoteRequest(NettyTest.java:28)

Возвращаемое нами сообщение является нулевым, что имеет смысл, учитывая, что мы не удосужились написать декодер Давайте реализуем декодер тогда:

1
2
3
4
5
6
7
8
9
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) );
    }
}

Теперь, если мы снова запустим наш тест, все будет зеленым и счастливым. Теперь мы можем пойти и кодировать / декодировать некоторые более сложные структуры и соответственно обновить наш тест.