netty基础09_利用EmbeddedChannel做单元测试
时间:2020-05-29
本文章向大家介绍netty基础09_利用EmbeddedChannel做单元测试,主要包括netty基础09_利用EmbeddedChannel做单元测试使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
netty提供了一种特殊的Channel 实现——EmbeddedChannel用来测试ChannelHandler;
例如:想测试自己编写服务端解码器是否能正确解码;
想在程序中测试需要在客户端给服务端发送消息,不方便调试;
使用EmbeddedChannel可以做到本地调试解码器;
1.EmbeddedChannel的api
2.运行机制
可以在EmbeddedChannel的有参构造中添加ChannelHandler;
EmbeddedChannel channel = new EmbeddedChannel(new MyDecoder());
对于入站消息:
调用EmbeddedChannel的writeInbound方法将数据写入管道;
数据会被管道中的入站处理器处理;
然后可以调用readInbound方法的到处理后的数据,看处理后的数据是否符合预期;
对于出站消息:
和入站消息的处理方法类似,只不过调用的方法不同;
调用writeOutbound方法,将出站的数据写入管道;
数据会被管道中的出站处理器处理;
调用readOutbound方法可以得到处理后的数据,看是否被正确处理;
3.测试
工具类HexUtil:用来将字节数组转换成十六进制字符串;
public class HexUtil { private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; public static byte[] decode(char[] data) { int len = data.length; if ((len & 0x01) != 0) { throw new IllegalArgumentException("Odd number of characters."); } byte[] out = new byte[len >> 1]; // two characters form the hex value. for (int i = 0, j = 0; j < len; i++) { int f = toDigit(data[j], j) << 4; j++; f = f | toDigit(data[j], j); j++; out[i] = (byte) (f & 0xFF); } return out; } public static char[] encode(byte[] data) { return encode(data, DIGITS_UPPER); } private static char[] encode(byte[] data, char[] toDigits) { int l = data.length; char[] out = new char[l << 1]; // two characters form the hex value. for (int i = 0, j = 0; i < l; i++) { out[j++] = toDigits[(0xF0 & data[i]) >>> 4]; out[j++] = toDigits[0x0F & data[i]]; } return out; } public static String encodeString(byte[] data) { return new String(encode(data)); } private static int toDigit(char ch, int index) { final int digit = Character.digit(ch, 16); if (digit == -1) { throw new IllegalArgumentException("Illegal hexadecimal character " + ch + " at index " + index); } return digit; } }
1)入站消息测试
目的:解码器会将字节数组解码成一帧4个字节的消息,看是否正确解码;
解码器:
public class MyDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception { if(byteBuf.readableBytes() >= 4){ ByteBuf buf = byteBuf.readBytes(4); //从消息中读取4个字节,并放到消息列表 list.add(buf); } } }
测试类:可以用Junit来测试
@Test public void testInBound() throws Exception{ ByteBuf buf = Unpooled.buffer(); for(int i=0;i<6;i++){ buf.writeByte(i); } ByteBuf buf2 = Unpooled.buffer(); for(int i=0;i<10;i++){ buf2.writeByte(i+6); } EmbeddedChannel channel = new EmbeddedChannel(new MyDecoder()); //新建EmbeddedChannel对象用来测试解码器,构造方法中添加待测解码器实例 channel.writeInbound(buf); channel.writeInbound(buf2); channel.finish(); //总共将16个字节的数据写入到进站消息中 ByteBuf read = channel.readInbound(); //获取一条解码后数据,如果正确解码应该是前4个字节的数据; System.out.println(HexUtil.encodeString(ByteBufUtil.getBytes(read))); read.release(); read = channel.readInbound(); //再次获取解码后的数据,如果正确解码,应该是得到第5~8字节的数据 System.out.println(HexUtil.encodeString(ByteBufUtil.getBytes(read))); read.release(); read = channel.readInbound(); //9~12字节 System.out.println(HexUtil.encodeString(ByteBufUtil.getBytes(read))); read.release(); read = channel.readInbound(); //13~16字节 System.out.println(HexUtil.encodeString(ByteBufUtil.getBytes(read))); }
结果:可以看到4次获取解码后的消息,每次得到4个字节的数据,说明解码符合预期;
2)出站消息测试
编码器:继承自消息转消息编码器,将ByteBuf转为字符串
public class MyEncoder extends MessageToMessageEncoder<ByteBuf>{ @Override protected void encode(ChannelHandlerContext context, ByteBuf buf, List<Object> list) throws Exception { int size = buf.readableBytes(); while(buf.readableBytes() >= 4){ String hex = HexUtil.encodeString(ByteBufUtil.getBytes(buf.readBytes(4))); //每4个字节转换成一个字符串,存入出队消息列表中 list.add(hex); } } }
测试类:16个字节用编码器做消息转换,每4个字节转成一个字符串
@Test public void testOutBound(){ ByteBuf buf = Unpooled.buffer(); for(int i=0;i<16;i++){ buf.writeByte(i); } EmbeddedChannel channel = new EmbeddedChannel(new MyEncoder()); channel.writeOutbound(buf); channel.finish(); System.out.println((String)channel.readOutbound()); System.out.println((String)channel.readOutbound()); System.out.println((String)channel.readOutbound()); System.out.println((String)channel.readOutbound()); }
结果:将16字节的ByteBuf转换成了4个字符串
原文地址:https://www.cnblogs.com/ShiningArmor/p/12988444.html
- 网络安全黑暗森林法则:2015 ISC 深度回顾
- Codeforces 626G Raffles(贪心+线段树)
- window.opener.location 安全风险讨论
- Vijos P1497 立体图【模拟】
- Vijos P1127 级数求和【模拟】
- 新型漏洞:利用浏览器Cookie绕过HTTPS并窃取私人信息
- Vijos P1113 不高兴的津津【模拟】
- Linux下MySQL的彻底卸载和安装配置字符集
- Codeforces 626F Group Projects(滚动数组+差分dp)
- Vijos P1103 校门外的树【线段树,模拟】
- BZOJ 1061: [Noi2008]志愿者招募【单纯形裸题】
- SQL vs NoSQL:如何选择?
- 线性规划之单纯形法【超详解+图解】
- NodeJS 应用仓库钓鱼
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- JVM详解之:java class文件的密码本
- Sharding-Proxy的基本功能使用
- JVM详解之:运行时常量池
- Linux常用命令面试题(1)
- 机器学习必刷题-手撕推导篇(1)
- Python面试必刷题系列(3)
- Spark Love TensorFlow
- 用GPU加速Keras模型——Colab免费GPU使用攻略
- __init__和__new__的对比及单例模式
- 数据结构高频面试题-树
- Python面试必刷题系列(5)
- 外卖小哥
- 用 Python可视化神器 Plotly 动态演示全球疫情变化趋势
- 2个范例带你读懂TensorFlow2低阶API构建模型方法
- 2个范例带你读懂中阶API建模方法