Netty 框架学习 —— 单元测试


EmbeddedChannel 概述

ChannelHandler 是 Netty 程序的关键元素,所以彻底地测试它们应该是你的开发过程中的一个标准部分,EmbeddedChannel 是 Netty 专门为改进针对 ChannelHandler 的单元测试而提供的。Netty 提供了它所谓的 Embedded 传输,这个传输是 EmbeddedChannel 的功能,提供了通过 ChannelPipeline 传播事件的简便方法

这个方法是:将入站数据或者出站数据写入到 EmbeddedChannel 中,然后检查是否有任何东西到达 CHannelPipeline 的尾端。通过这种方式,你可以确定消息是否已经被编码或者解码过,以及是否触发了任何 ChannelHandler 动作

下表列出了 EmbeddedChannel 的相关方法

Netty 框架学习 —— 单元测试

入站数据由 ChannelInboundHandler 处理,代表从远程节点读取的数据。出站数据由 ChannelOutboundHandler 处理,代表将要写到远程节点的数据。根据你要测试的 ChannelHandler,你可以使用 Inbound() 或者 Outbound() 方法对,或者兼而有之

下图展示了使用 EmbeddedChannel 的方法,数据是如何流经 ChannelPipeline 的。 你可以使用 writeOutbound()方法将消息写到 Channel 中,并通过 ChannelPipeline 沿 着出站的方向传递。随后,你可以使用 readOutbound()方法来读取已被处理过的消息,以确 定结果是否和预期一样。类似地,对于入站数据,你需要使用 writeInbound()和 readInbound() 方法
![](G:\SSS\Java\Java SE\博客\Netty\EmbeddedChannel 的数据流.png)


使用 EmbeddedChannel 测试 ChannelHandler 1. 测试入站消息

下述代码展示了一个简单的 ByteToMessageDecoder 实现,给定足够的数据,这个实现将产生固定大小的帧。如果没有足够的数据可供读取,它将等待下一个数据块的到来,并将再次检查是否能够产生一个新的帧

public class FixedLengthFrameDecoder extends ByteToMessageDecoder { // 指定要生成的帧的长度 private final int frameLength; public FixedLengthFrameDecoder(int frameLength) { if (frameLength <= 0) { throw new IllegalArgumentException("frameLength must be a positive integer:" + frameLength); } this.frameLength = frameLength; } @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { //检查是否有足够的字节可以被读取,以生成下一个帧 while (in.readableBytes() >= frameLength) { //从 ByteBuf 中读取一个新帧 ByteBuf buf = in.readBytes(frameLength); //将该帧添加到已被解码的消息列表中 out.add(buf); } } }

下述代码展示了使用 EmbeddedChannel 的对于前面代码的测试

public class FixedLengthFrameDecoderTest { @Test public void testFrameDecoded() { //创建一个 ByteBuf,并存储 9 字节 ByteBuf buf = Unpooled.buffer(); for (int i = 0; i < 9; i++) { buf.writeByte(i); } ByteBuf input = buf.duplicate(); EmbeddedChannel channel = new EmbeddedChannel(new FixedLengthFrameDecoder(3)); //将数据写入 EmbeddedChannel System.out.println(channel.writeInbound(input.retain()));//true //标记 Channel 为已完成状态 System.out.println(channel.finish());//true //读取所生成的消息,并且验证是否有 3 帧,其中每帧都为 3 字节 ByteBuf read = channel.readInbound(); System.out.println(buf.readSlice(3).equals(read));// true read = channel.readInbound(); System.out.println(buf.readSlice(3).equals(read));// true read.release(); read = channel.readInbound(); System.out.println(buf.readSlice(3).equals(read));// true read.release(); System.out.println(channel.readInbound() == null);// true buf.release(); } @Test public void testFramesDescode2() { ByteBuf buf = Unpooled.buffer(); for (int i = 0; i < 9; i++) { buf.writeByte(i); } ByteBuf input = buf.duplicate(); EmbeddedChannel channel = new EmbeddedChannel(new FixedLengthFrameDecoder(3)); //返回 false,因为没有一个完整的可供读取的帧 System.out.println(channel.writeInbound(input.readBytes(2)));// false System.out.println(channel.writeInbound(input.readBytes(7)));// true System.out.println(channel.finish());// true ByteBuf read = channel.readInbound(); System.out.println(buf.readSlice(3) == read);// false read.release(); read = channel.readInbound(); System.out.println(buf.readSlice(3) == read);// false read.release(); read = channel.readInbound(); System.out.println(buf.readSlice(3) == read);// false read.release(); System.out.println(channel.readInbound() == null);// true buf.release(); } } 2. 测试入站消息

测试出站消息的处理过程和刚才所看到的类似,在下面的例子中,我们将会展示如何使用 EmbeddedChannel 来测试另一个编码器形式的 ChannelOutboundHandler,编码器是一种将一种消息格式转换为另一种的组件

该示例将会按照下列方式工作:

持有 AbsIntegerEncoder 的 EmbeddedChannel 将会以 4 字节的负整数的形式写出站数据

编码器将从传入的 ByteBuf 中读取每个负整数,并将会调用 Math.abs() 方法来获取其绝对值

编码器将会把每个负整数的绝对值写到 ChannelPipeline 中

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwwwwj.html