概述
前面的章节已经对 Netty 的各个组件进行了学习即使用。了解到 Netty 在使用的过程中,基本上所有的程序逻辑部分的主体都是在 ChannelHandler 中完成的,所以对 ChannelHandler 进行认真仔细的测试是很重要的一个环节了。那么,如何很好的测试 ChannelHandler 了?答案就是 EmbededChannel 。
EmbededChannel
EmbededChannel 其实就是 Netty 提供的一种特殊的 Channel,主要功能就是验证 ChannelPipeLine 中 ChannelHandler 编写的逻辑是否正常。它的实现原理,简单说来就是:把入站或者出站数据写入到 EmbededChannel 中,然后通过 EmbededChannel 提供的方法验证这些数据是否正常的通过所有的 ChannelHandler。如果通过了,则正确;否则就是错误的。它提供了如下方法
名称 | z作用 |
writeInbound(Object...msgs) | 将入站数据写到 EmbededChannel 中。然后通过 readInbound()方法从 EmbededChannel 中读取数据,则返回 true |
readInbound() | 从 EmbededChannel 中 读取一个入站的消息。任何返回的结果都是穿越了整个 ChannelPipeLine 的。如果没有任何可供读取的,则返回 null |
writeOutbound(Object...msgs) | 将出站数据写到 EmbededChannel 中。然后通过 readOutbound()方法从 EmbededChannel 中读取数据,则返回 true |
readOutbound() | 从 EmbededChannel 中 读取一个出站的消息。任何返回的结果都是穿越了整个 ChannelPipeLine 的。如果没有任何可供读取的,则返回 null |
finish() | j将 EmbededChannel 标记为完成,并且如果有可被读取的入站数据或者出站数据,则返回 true。这个方法还将会调用 EmbededChannel 上的 close()方法 |
如下图展示了 EmbededChannel 验证 ChannelHandler 的原理
EmbededChannel 的使用示例
编写一个 FrameChunkDecoder 的 ChannelHandler,该 handler 的作用是限制每一帧数据的大小不超过 4 个字节,如果超过了则会抛出异常。
FrameChunkDecoder 类
import java.util.List;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.TooLongFrameException;
public class FrameChunkDecoder extends ByteToMessageDecoder{
private final int maxFrameSize;
//指定允许产生的最大的帧长度
public FrameChunkDecoder(int maxFrameSize){
this.maxFrameSize = maxFrameSize;
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
int readableBytes = in.readableBytes();
if(readableBytes > maxFrameSize){
//discard the bytes
in.clear();
throw new TooLongFrameException();
}
ByteBuf buf = in.readBytes(readableBytes);
out.add(buf);
}
}
FrameChunkDecoderTest 类
import static org.junit.Assert.*;
import org.junit.Assert;
import org.junit.Test;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.TooLongFrameException;
public class FrameChunkDecoderTest{
@Test
public void testFrameDecoded(){
ByteBuf buf = Unpooled.buffer();
for (int i = 0; i < 9; i++) {
buf.writeByte(i);
}
ByteBuf input = buf.duplicate();
EmbeddedChannel channel = new EmbeddedChannel(new FrameChunkDecoder(3));
//向 EmbededChannel 中写入 2 字节,并且断言他们将会产生一个新帧
assertTrue(channel.writeInbound(input.readBytes(2)));
try{
//写入一个 4 帧大小的数据,并且捕获抛出来的异常
channel.writeInbound(input.readBytes(4));
Assert.fail();
}catch(TooLongFrameException e){
System.out.println("Frame too long");
}
assertTrue(channel.writeInbound(input.readBytes(3)));
//将channel 标记为已完成的状态
assertTrue(channel.finish());
//***读取帧*//
ByteBuf read = channel.readInbound();
//确定第一帧是否是2个字节
assertEquals(buf.readSlice(2), read);
read.release();
read = channel.readInbound();
//跳过 4 个字节,直接读取最后 3 个字节
assertEquals(buf.skipBytes(4).readSlice(3), read);
read.release();
buf.release();
}
}
总结
采用 Junit 测试工具来进行单元测试是一种非常有效的方式。本章节通过 Junit 和 EmbededChannel 来实现了对ChannelHandler 测试,可以感受到测试是如此的有效和简单。下一章节将对 Netty 的编解码器进行学习