一、概述和原理
Netty 的單元測試,主要是對業務邏輯的 ChannelHandler 做測試(畢竟對 Bootstrap、EventLoop 這些做測試着實沒有多大意義),模擬一次入站數據或者出站數據,查看數據流經 ChannelHandler 變成什么樣了,以此達到測試的目的。
Netty 的單元測試將Junit4作為測試框架,將 EmbeddedChannel 作為測試通道。基本原理就是:將入站數據或者出站數據寫入 EmbeddedChannel 中,然后檢查是否有任何東西到達了 ChannelPipeline 的尾端。以這種方式,你便可以知道消息是否流經了 ChannelHandler 以及是否觸發了任何 ChannelHandler 的動作,如下圖:
EmbeddedChannel 提供了如下方法進行單元測試:
writeInbound(Object... msgs): 將入站消息寫到 EmbeddedChannel 中。如果可以通過 readInbound()方法從 EmbeddedChannel 中讀取數據,則返回 true。
readInbound() :從 EmbeddedChannel 中讀取一個入站消息。任何返回的東西都穿越了整個 ChannelPipeline。如果沒有任何可供讀取的, 則返回 null。
writeOutbound(Object... msgs): 將出站消息寫到EmbeddedChannel中。如果現在可以通過readOutbound()方法從 EmbeddedChannel 中讀取到什么東西,則返回 true。
readOutbound(): 從 EmbeddedChannel 中讀取一個出站消息。任何返回的東西都穿越了整個 ChannelPipeline。如果沒有任何可供讀取的,則返回 null。
finish() :將 EmbeddedChannel 標記為完成,並且如果有可被讀取的入站數據或者出站數據,則返回 true。這個方法還將會調用 EmbeddedChannel 上的close()方法。
二、測試入站數據
1、將我們要測試的 ChannelHandler 寫入 EmbeddedChannel 進行測試。
2、writeInbound(Object... msgs) 將數據寫入EmbeddedChannel(模擬接收數據)。
3、ChannelHandler 處理后如果有返回數據,可以通過readInbound() 驗證數據結果。如果沒有返回數據,可以在 ChannelHandler 業務邏輯中,打印日志,以達到測試目的。
public class DecoderTest { //1、利用Junit執行單元測試 @Test public void decoderTest() throws IllegalAccessException { ByteBuf buf = Unpooled.buffer(); for (int i = 0; i < 9; i++) { buf.writeByte(i); } ByteBuf buf1 = buf.duplicate(); //2、創建EmbeddedChannel,並添加一個Decoder(我們的要測試 ChannelHandler) 其將以3字節幀長度被測試 EmbeddedChannel embeddedChannel = new EmbeddedChannel(new Decoder(3)); //3、將數據寫入 EmbeddedChannel boolean writeInbound = embeddedChannel.writeInbound(buf1.retain()); assertTrue(writeInbound); //4、標記 Channel 為已完成狀態 boolean finish = embeddedChannel.finish(); assertTrue(finish); //5、讀取數據 ByteBuf readInbound = embeddedChannel.readInbound(); ByteBuf readSlice = buf.readSlice(3); assertEquals(readInbound, readSlice); readInbound.release(); readInbound = embeddedChannel.readInbound(); readSlice = buf.readSlice(3); assertEquals(readInbound, readSlice); readInbound.release(); readInbound = embeddedChannel.readInbound(); readSlice = buf.readSlice(3); assertEquals(readInbound, readSlice); readInbound.release(); //是否讀取完數據了 assertNull(embeddedChannel.readInbound()); //釋放資源 buf.release(); } }
三、測試出站數據
1、將我們要測試的 ChannelHandler 寫入 EmbeddedChannel 進行測試。
2、writeOutbound(Object... msgs) 將數據寫入EmbeddedChannel(模擬發送數據)。
3、ChannelHandler 處理后如果有返回數據,可以通過readOutbound() 驗證數據結果。如果沒有返回數據,可以在 ChannelHandler 業務邏輯中,打印日志,以達到測試目的。
public class EncoderTest { @Test public void encoderTest(){ ByteBuf buf = Unpooled.buffer(); for (int i =1; i < 10; i++){ buf.writeInt(i * -1); } //1、創建一個EmbeddedChannel 並安裝要測試的Encoder EmbeddedChannel embeddedChannel = new EmbeddedChannel(new Encoder()); //2、寫入數據 assertTrue(embeddedChannel.writeOutbound(buf)); assertTrue(embeddedChannel.finish()); //3、讀取數據 for (int i = 1; i < 10; i++){ Object o = embeddedChannel.readOutbound(); System.out.println(o); } assertNull(embeddedChannel.readOutbound()); } }
四、結語
截止到這篇文章,Netty 的基礎部分差不多就結束了。不幸的是,公司安排我去研究下 Docker 技術,想在我們項目中使用起來。所以 Netty 的學習就不得不告一段落了~~才翻完《Netty 實戰》一半的內容,后面還有編解碼器、網絡協議、案例研究三個部分,只能先欠下了~
參考資料:《Netty IN ACTION》
演示源代碼:https://github.com/JMCuixy/NettyDemo/tree/master/src/main/java/org/netty/demo/unit