一种特殊的Channel实现----EmbeddedChannel,它是Netty专门为改进针对ChannelHandler的单元测试而提供的。

名称 职责
writeInbound 将入站消息写到EmbeddedChannel中。如果可以通过readInbound方法从EmbeddedChannel中读取数据,则返回true
readInbound 从EmbeddedChannel中读取入站消息。任何返回东西都经过整个ChannelPipeline。如果没有任何可供读取的,则返回null
writeOutbound 将出站消息写到EmbeddedChannel中,如果现在可以通过readOutbound从EmbeddedChannel中读取到东西,则返回true
readOutbound 从EmbeddedChannel中读取出站消息。任何返回东西都经过整个ChannelPipeline。如果没有任何可供读取的,则返回null
finish 将EmbeddedChannel标记为完成,如果有可读取的入站或出站数据,则返回true。这个方法还将会调用EmbeddedChannel上的close方法

测试入站消息

public class FixedLengthFrameDecoder extends ByteToMessageDecoder {
private final int frameLength; public FixedLengthFrameDecoder(int frameLength) {
if (frameLength <= 0) {
throw new IllegalArgumentException("frameLength must be positive integer: " + frameLength);
}
this.frameLength = frameLength;
} @Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
while (in.readableBytes() >= frameLength) {
ByteBuf buf = in.readBytes(frameLength);
out.add(buf);
}
}
}
public class FixedLengthFrameDecoderTest {
@Test
public void testFramesDecoded() {
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));
Assert.assertTrue(channel.writeInbound(input.retain()));
Assert.assertTrue(channel.finish()); ByteBuf read = channel.readInbound();
Assert.assertEquals(buf.readSlice(3), read);
read.release(); read = channel.readInbound();
Assert.assertEquals(buf.readSlice(3), read);
read.release(); read = channel.readInbound();
Assert.assertEquals(buf.readSlice(3), read);
read.release(); Assert.assertNull(channel.readInbound());
buf.release();
} @Test
public void testFramesDecoded2() {
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));
Assert.assertFalse(channel.writeInbound(input.readBytes(2)));
Assert.assertTrue(channel.writeInbound(input.readBytes(7)));
Assert.assertTrue(channel.finish());
ByteBuf read = channel.readInbound();
Assert.assertEquals(buf.readSlice(3), read);
read.release(); read = channel.readInbound();
Assert.assertEquals(buf.readSlice(3), read);
read.release(); read = channel.readInbound();
Assert.assertEquals(buf.readSlice(3), read);
read.release(); Assert.assertNull(channel.readInbound());
buf.release();
}
}

测试出站消息

public class AbsIntegerEncoder extends MessageToMessageEncoder<ByteBuf> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> out) throws Exception {
while (in.readableBytes() >= 4) {
int value = Math.abs(in.readInt());
out.add(value);
}
}
}
public class AbsIntegerEncoderTest {
@Test
public void testEncoded() {
ByteBuf buf = Unpooled.buffer();
for (int i = 0; i < 10; i++) {
buf.writeInt(i * -1);
}
EmbeddedChannel channel = new EmbeddedChannel(new AbsIntegerEncoder());
Assert.assertTrue(channel.writeOutbound(buf));
Assert.assertTrue(channel.finish()); for (int i = 0; i < 10; i++) {
Assert.assertEquals(Integer.valueOf(i), channel.readOutbound());
}
Assert.assertNull(channel.readOutbound());
}
}

测试异常处理

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) {
in.clear();
throw new TooLongFrameException();
}
ByteBuf buf = in.readBytes(readableBytes);
out.add(buf);
}
}
public class FrameChunkDecoderTest {
@Test
public void testFramesDecoded() {
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));
Assert.assertTrue(channel.writeInbound(input.readBytes(2)));
try {
channel.writeInbound(input.readBytes(4));
Assert.fail();
} catch (TooLongFrameException e) { }
Assert.assertTrue(channel.writeInbound(input.readBytes(3)));
Assert.assertTrue(channel.finish()); ByteBuf read = channel.readInbound();
Assert.assertEquals(buf.readSlice(2), read);
read.release(); read = channel.readInbound();
Assert.assertEquals(buf.skipBytes(4).readSlice(3), read);
read.release();
buf.release();
}
}

netty使用EmbeddedChannel对channel的出入站进行单元测试的更多相关文章

  1. 自顶向下深入分析Netty(六)--Channel总述

    自顶向下深入分析Netty(六)--Channel总述 自顶向下深入分析Netty(六)--Channel源码实现 6.1 总述 6.1.1 Channel JDK中的Channel是通讯的载体,而N ...

  2. Netty那点事: 概述, Netty中的buffer, Channel与Pipeline

    Netty那点事(一)概述 Netty和Mina是Java世界非常知名的通讯框架.它们都出自同一个作者,Mina诞生略早,属于Apache基金会,而Netty开始在Jboss名下,后来出来自立门户ne ...

  3. netty做集群 channel共享 方案

    netty做集群 channel如何共享? 方案一: netty 集群,通过rocketmq等MQ 推送到所有netty服务端, channel 共享无非是要那个通道都可以发送消息向客户端, MQ广播 ...

  4. Netty源码分析之ChannelPipeline—入站事件的传播

    之前的文章中我们说过ChannelPipeline作为Netty中的数据管道,负责传递Channel中消息的事件传播,事件的传播分为入站和出站两个方向,分别通知ChannelInboundHandle ...

  5. Netty源码分析之ChannelPipeline—出站事件的传播

    上篇文章中我们梳理了ChannelPipeline中入站事件的传播,这篇文章中我们看下出站事件的传播,也就是ChannelOutboundHandler接口的实现. 1.出站事件的传播示例 我们对上篇 ...

  6. Netty源码分析--Channel注册(上)(五)

    其实在将这一节之前,我们来分析一个东西,方便下面的工作好开展. 打开启动类,最开始的时候创建了一个NioEventLoopGroup 事件循环组,我们来跟一下这个. 这里bossGroup, 我传入了 ...

  7. Netty源码分析--Channel注册(中)(六)

    接上一篇,我们继续看 不知道大家第一次看这段代码的时候有没有一脸懵逼,反正我是一脸懵,为什么这个if else 最终都是调用的register0方法,都是一样的. 其实这里就是为什么Netty是线程安 ...

  8. 003——Netty之Buffer、Channel以及多路复用器Selector

    Buffer 1.缓冲区类型 2.缓冲区定义 (1)Buffer是一个对象,其中包含写入与读出的数据.是新IO与原IO的重要区别.任何情况下访问NIO中的数据都需要通过缓存区进行操作. (2)Buff ...

  9. netty(五) channel

    问题 channel 是如何处理发送一半中断后继续重发的 channel 具体作用是什么 概述 这一节我们将介绍 Channel 和内部接口 Unsafe .其中Unsafe 是内部接口,聚合在Cha ...

随机推荐

  1. 微信小程序商城(Java版)

    体验 后台演示地址(账号:admin 密码:admin) 小程序体验如下: 技术选型 1 后端使用技术 1.1 springframework4.3.7.RELEASE 1.2 mybatis3.1. ...

  2. 【记录】Field required a single bean, but 2 were found:

    重构遇到个小问题,记录下: 错误信息: *************************** APPLICATION FAILED TO START ************************ ...

  3. lunix杂记_scp与vi编辑器

    1.scp命令,复制其它服务器资源 scp 用户名@192.168.0.9:/usr/local/apache-tomcat-7.0.68 ./ scp -f  username@192.168.0. ...

  4. 私服 Nexus 的配置 (转)

    https://www.cnblogs.com/yuanermen/p/4574473.html 一.概述 1.概要 现在的项目基本都是用Maven来管理工程,这样一来在公司内容搭建一个私服就非常有必 ...

  5. php5.3之命名空间

    在php5.3之后,php像c++那样新 命名空间. 1.在同一个文件中不能实例化同一个名字相同的类和同时包含两个不同目录下的相同文件,中包含相同的函数和常量.为了解决这个问题,因此引入了命名空间. ...

  6. 一路编程 -- Gruntfile.js

    <一路编程> Steven Foote 第四章构建工具 中的 Gruntfile.js 文件的 JSHint 部分,如果按照书中所写,run  grunt 的命令的时候会出错. 此处附上完 ...

  7. Programming In Lua 第二章

    1,lua基本类型:nil,boolean,number,string,userdata,function,thread,table.可以用函数type获取变量的类型. 2,lua中的字符串可以用单引 ...

  8. C#学习笔记:ListBox控件的用法

    样式如下: 实现的代码一: using System;using System.Collections.Generic;using System.ComponentModel;using System ...

  9. URL的命名和反向解析

    1. 分组 url(r'^del_publisher/(\d+)', views.del_publisher), 匹配到参数,按照位置参数的方式传递给视图函数 视图函数需要定义形参接收变量 2. 命名 ...

  10. Oracle数据库---游标

    --查询所有员工的员工号.姓名和职位的信息.DECLARE --定义游标 CURSOR emp_cursor IS SELECT empno,ename,job FROM emp; v_empno e ...