1. 程式人生 > >Netty 系列五(單元測試).

Netty 系列五(單元測試).

github 處理 執行 margin pre image null 取數據 eventloop

一、概述和原理

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

Netty 系列五(單元測試).