本章内容包括:

1)单元测试

2)EmbeddedChannel的说明

3)使用EmbeddedChannel测试ChannelHandler

对于一个Netty应用来说,ChannelHandler是一个至关重要的元素,所以充分地去测试ChannelHandler应该是你开发过程中必要的组成部分,我们的最佳实践会告诉你测试不仅能保证你的具体实现的正确性,更重要的是,当你突然变更你的代码的时候,它能很容易地去隔离问题,这种类型的测试叫做单元测试

尽管对单元测试大家没有一个完整的定义,但是更多的参与者觉得单元测试是基础的,是必要的,单元测试的理念基本上是这样:测试尽可能小的代码块,尽可能的隔离其他模块或者是运行时的依赖,数据库网络等带来的影响,如果你验证每一个单元模块的它本身的正确性的话,你会发现当出现bug时,你会很容易找到问题的根源

在这个章节,我们将学习一个特殊的Channel的实现-----EmbededChannel,这个类是由Netty提供的,指定用来构建对ChannelHandler的单元测试的基本建设类

因为代码模块或者代码单元将会脱离它正常的运行环境去做测试,或者你需要一个框架或者工具来运行测试它,在我们所有的例子中,我们使用JUnit4作为我们的测试框架,所以我们需要对JUnit4有着一些基本的了解,如果你对JUnit4完全不了解的话,不要慌张,JUnit4是简单且强大的框架,你可以去www.junit.org网站上去稍微了解一下Junit4一些基本的知识,在这个网站里有你想要知道的一切

9.1 Overview of EmbeddedChannel

你已经掌握了ChannelHandler的一些具体实现可以链式的放入ChannelPipeline中用来构建你应用的业务逻辑模块的实现,我们之前也解释过,这种设计可以把一些潜在的复杂的业务逻辑处理分解成迷你的可重复利用的组件,分解后的Handler都是一个明确的任务或者步骤,在这个章节中,我们也会教你如何简化测试

Netty提供了一个名为嵌入式的传输服务用来测试ChannelHandler,这个传输服务是特殊Channel实现EmbededChannel的一个特性,它可以提供一个简单的方式来让所有的事件通过管道

这个想法是直接有效的,你写入输入输出数据到EmbededChannel中,然后检测是否有内容能够正确地传输到ChannelPipeline的末端,通过这个方法你可以确定消息是否被正确的编码或者解码,是否每一个ChannelHandler定义的动作都被触发执行了

EmbededChannel的一些相关的方法在表9.1中展示了

输入数据将被ChannelInboundHandler处理代表着从远程端接收数据,输出数据代表被ChannelOutboundChannel处理,代表发送数据到远程端,在测试过程中你可能使用*Inbound或者*Outbound类似这样的方法去测试或者两种方法都使用,这都依赖于你测试的是哪种ChannelHandler

图9.1展示了使用EmbededChannel的方法的时候,数据如何通过ChannelPipeline的情形,你可以使用writeOutbound方法去写入一个message到Channel中,然后这个信息会以输出方向通过ChannelPipeline,随后你可以用readOutbound方法去读取被处理的信息,来确定读取的结果是否与我们预期的结果一样,简而言之,对于输入数据,你可以使用writeInbound或者readInbound方法

在每一个案例中,信息在通过ChannelPipeline中的时候,都是被相关的Handler处理的,要么是ChannelInboundHandler要么是ChannelOutboundHandler,如果消息还没有被消费,你可以使用readInbound或者readOutbound方法在适当的时候读取从channel中出来的信息

让我们详细地讲解一下这两种场景吧,看看他们是如何被应用到你的测试场景中去的

9.2 Testing ChannelHandlers with EmbeddedChannel

在这个小节中,我们将讲解如何使用EmbededChannel测试一个ChannelHandler

TIPS:JUnit assertions

org.junit.Assert类提供了很多静态的方法用来测试,一个失败的断言将会导致一个异常被抛出,并且会终止当前的测试,我们可以使用静态导入的方式来引入这些断言,这将会是一个很高效的方法

9.2.1 Testing inbound messages

图92展示了一个简单的ByteToMessageDecoder实现,给予足够的数据,ByteToMessageDecoder会产生出固定大小的帧数据,如果没有足够数量的数据被读取,它将会等待下一个块中的数据,等下一个块数据到达的时候,再次判断是否可以生成出一个固定大小的帧数据

我们可以看出右边的帧数据的图形,这个特制的解码器可以生成出3个字节固定大小的帧数据,也就是说,当一个事件触发的时候需要带来足够的字节数来生产一个帧数据

最后生产出来的帧数据会被传播到ChannelPipeline中的下一个管道中去

这个解码器的具体实现如下面的代码清单所示:

现在我们编写一个单元测试类来测试这个解码器是否能够按照我们预期的一样去执行,我们之前就提过很多次,即使是一个很简单的代码块,单元测试可以帮助我们在代码重构的期间阻止一些问题的发生或者在问题发生的时候,可以很轻松地诊断出问题的所在

下面是使用EmbededChannel来测试上面解码器的代码

方法testFramesDecoded验证了当一个ByteBuf中包含9个可读字节的时候,可以被分成3个全新的ByteBuf,每一个ByteBuf中包含3个字节,注意到一个拥有9个字节的ByteBuf调用了writeInboud方法,然后finish方法被执行标志着EmbededChannel完成,最后readInbound方法被调用用来从EmbededChannel中精确地读取三个帧数据和一个null值

testFramesDecoded2方法是简单的,与方法一只有唯一的一点不同,在输入ByteBuf的写入的时候分了2个步骤,当writeInbound(input.readBytes(2))方法被调用的时候,返回了false,这是为什么呢?我们在表9.1中陈述过,如果对于后来对应的readInboud方法能够返回数据,那么writeInbound方法将会返回true,但是我们这个案例中的FixedLengthFrameDecoder只会在输入的字节数等于或者超过3个字节的时候才会产出数据,接下来的测试就会与testFramesDecoded一样了

9.2.2 Testing outbound messages

测试输出信息的过程与我们刚刚写的输入信息测试是很相似的,在接下来的一个例子中,我们将向你展示如何使用EmbededChannel去测试一个编码器类型的ChannelOutboundHandler,这个组件可以将一个信息从一个格式转化成另一个格式,我们将会在下面的一个章节详细地讲解编码器和解码器,目前为止,我们只是在我们测试过程中,简单地提及一下,AbsIntegerEncoder,这是Netty的MessageToMessageEncoder的一个具体实现,用来将负值的Integer转化成它的绝对值

这个例子会如下工作:

1)一个EmbededChannel会持有一个AbsIntegerEncoder,会写入四个字节的负值Integer类型的数据

2)解码器将会从每个ByteBuf中读取负值,然后调用Math.abs()方法来获取他们的绝对值

3)解码器会将每个Integer的绝对值写入到ChannelPipeline中

图9.3展示了这个逻辑

下面的代码清单实现了图9.3的逻辑,encode方法将生产的值放入到List中

下面的代码清单使用EmbededChannel测试了上面的代码块

在这段代码中有一下几个比较重要的步骤:

①写入四字节的负值Integer类型的变量到ByteBuf中

②创建一个EmbededChannel并且分配一个AbsIntegerEncoder给EmbededChannel

③在EmbededChannel中调用writeOutChannel方法写入ByteBuf

④标记channel已经完成

⑤从EmbededChannel的输出端读取所有的Integer类型,然后验证输出数据是不是全部是绝对值

9.3 Testing exception handling

在应用中除了要处理传输数据之外,还会有一些其他的任务,例如,你有时候需要处理畸形数据或者超大数据,在下面的一个例子中,如果读取的字节的数量超过了我们固定的一个限制时,我们会抛出一个TooLongFrameException的异常,这种方式经常使用来防止资源短缺

在图9.4中,我们规定最大的帧数据的大小不能超过三个字节,如果某个帧数据的大小超过了这个限制的话,它的字节数将被消除且会将TooLongFrameException的异常抛出,

在管道中的其他ChannelHandler可以去处理这个异常也可以直接忽视这个异常

下面的代码给出了具体的实现

同样,我们再次使用EmbededChannel测试一下上面的代码

如果对上面的代码只是轻轻一瞥的话,你会发现这个代码与9.2的代码清单看起来很类似,但只有一个小小的不同,其实就是对TooLongFrameException的处理不同,在这里我们用try/catch块包裹住这个代码块其实是EmbededChannel的一个特性,如果其中一个write方法抛出了一个异常的话,它将会以运行时异常的形式抛出,这让测试将变得很简单,因为你可以选择是否在处理数据的过程中处理异常

在这里测试方法是可以用在任何可以抛出异常的ChannelHandler的实现里的

9.4 Summary

用专业的测试工具JUnit来做单元测试会是一个极佳的方法来保证你的代码的正确性并且会提高你代码的可维护性,在这个章节中我们学些了Netty提供的一些测试工具类来测试你自定义的ChannelHandler

在下一个章节中,我们将聚焦于写出一个真实可用的Netty应用,我们将不会再展示任何测试的代码类,所以我们希望你将这个章节讲解的测试方法牢记心中

Netty in Action (十九) 第九章节 单元测试相关推荐

  1. 【系统分析师之路】第十九章 知识产权与标准化(章节重点)

    [系统分析师之路]第十九章 知识产权与标准化(章节重点) 第十九章 知识产权与标准化章节重点 [系统分析师之路]第十九章 知识产权与标准化(章节重点) 章节重点 一. 保护范围与对象(★★★) 1)著 ...

  2. Netty In Action中文版 - 第十二章:SPDY

    Netty In Action中文版 - 第十二章:SPDY 本章我将不会直接翻译Netty In Action书中的原文,感觉原书中本章讲的很多废话,我翻译起来也吃力.所以,本章内容我会根据其他资料 ...

  3. 《东周列国志》第九十九回 武安君含冤死杜邮 吕不韦巧计归异人

    话说赵孝成王初时接得赵括捷报,心中大喜,已后闻赵军困于长平,正欲商量遣兵救援,忽报:"赵括已死,赵军四十余万尽降于秦,被武安君一夜坑杀,止放二百四十人还赵."赵王大惊,群臣无不悚惧 ...

  4. Netty In Action中文版

    第一章:Netty介绍 本章介绍 Netty介绍 为什么要使用non-blocking IO(NIO) 阻塞IO(blocking IO)和非阻塞IO(non-blocking IO)对比 Java ...

  5. bmp文件头_「正点原子FPGA连载」第十九章SD卡读BMP图片LCD显示

    1)摘自[正点原子]领航者 ZYNQ 之嵌入式开发指南 2)实验平台:正点原子领航者ZYNQ开发板 3)平台购买地址:https://item.taobao.com/item.htm?&id= ...

  6. 十九、Android Activity初探

    原文:十九.Android Activity初探 Activity是一个应用中的组件,它为用户提供一个可视的界面,方便用户操作,比如说拔打电话.照相.发邮件或者是浏览地图等.每个activity会提供 ...

  7. 鸟哥的Linux私房菜(基础篇)- 第十九章、认识与分析登录文件

    第十九章.认识与分析登录文件 最近升级日期:2009/09/14 当你的 Linux 系统出现不明原因的问题时,很多人都告诉你,你要查阅一下登录文件才能够知道系统出了什么问题了,所以说,了解登录文件是 ...

  8. 第三百一十九节,Django框架,文件上传

    第三百一十九节,Django框架,文件上传 1.自定义上传[推荐] 请求对象.FILES.get()获取上传文件的对象 上传对象.name获取上传文件名称 上传对象.chunks()获取上传数据包,字 ...

  9. SAP UI5 应用开发教程之三十九 - SAP UI5 应用出现白屏的一些常见错误和分析方法分享试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

最新文章

  1. 浏览器设置是否显示图片,可随时切换
  2. linux如何安装VM虚拟机
  3. 我第一次接私活,就被骗了···
  4. 我理解的【旁路代理】
  5. iOS之深入解析事件传递的响应链
  6. 教学一体机属于计算机的什么应用,教学一体机跟电脑有什么区别 让教学氛围有着更好的教学效果...
  7. Linux基础命令介绍七:网络传输与安全
  8. 【NOIP2010】【P1317】乌龟棋
  9. 依赖项出现感叹号怎么办_SpringBoot中如何对依赖进行管理?
  10. FreeRTOS队列集
  11. 【转】iOS编译OpenSSL静态库(使用脚本自动编译)
  12. 【测试篇】为什么需要测试
  13. linux+镜像命令在哪里,怎么查看 linux 镜像文件
  14. C/C++项目源码——数字雨DigitalRain
  15. Euraka配置详解
  16. m4s格式转换mp3_amr转换mp3格式文件
  17. eclipse maven 安装
  18. 让Mac文本编辑器成为HTML编辑器
  19. Scratch编程 烧脑算法——换位密码
  20. 小米手机miui12稳定版蓝牙时断不稳定的解决办法。

热门文章

  1. 利用PS的磁性套索工具进行抠图
  2. 弱电机房工程搬迁工作内容(方案)
  3. socket closed解决办法
  4. 高项_第十三章项目合同管理
  5. 概率论中的矩母函数(MGF)
  6. 2022-JavaScript-过滤数组中的undefined,null,空串,NaN
  7. QQ工具手机软件+实用小软件+恶搞小软件合集
  8. php gd表情包,gd表情包
  9. Spring Data JPA 多条件判空查询
  10. 一道疯狂bypass的题目