Netty 使用 EmbeddedChannel 進行單元測試

Netty 使用 EmbeddedChannel 進行單元測試


對於 Netty 的 ChannelHandler 進行單元測試,Netty 提供了 EmbeddedChannel 嵌入式通道來完成這一過程,主要使用該通道來測試數據的入站出站過程是否合法;
該通道提供以下常用的 API:
writeInbound 寫一個入站消息到 EmbeddedChannel。 如果數據能從 EmbeddedChannel 通過 readInbound() 讀到,則返回 true;
readInbound 從 EmbeddedChannel 讀到入站消息。任何返回遍歷整個ChannelPipeline。如果讀取還沒有準備,則此方法返回 null;
writeOutbound 寫一個出站消息到 EmbeddedChannel。 如果數據能從 EmbeddedChannel 通過 readOutbound() 讀到,則返回 true;
readOutbound 從 EmbeddedChannel 讀到出站消息。任何返回遍歷整個ChannelPipeline。如果讀取還沒有準備,則此方法返回 null;
Finish 如果從入站或者出站中能讀到數據,標記 EmbeddedChannel 完成並且返回。這同時會調用 EmbeddedChannel 的關閉方法;
完整 API 見:http://netty.io/4.1/api/io/netty/channel/embedded/EmbeddedChannel.html

以下圖示了 ChannelPipeline 使用 EmbeddedChannel 的方法:



入站處理器測試

以下測試一個入站解碼器 FixedLengthFrameDecoder;
FixedLengthFrameDecoder
 
//用於進行測試的 Decoder,將讀取的幀分隔爲固定長度
public class FixedLengthFrameDecoder extends ByteToMessageDecoder {
    private final int frameLength;   //幀長度
    public FixedLengthFrameDecoder(int frameLength) {
        this.frameLength = frameLength;
    }
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        //幀分割
        while(in.readableBytes() >= frameLength)
            out.add(in.readBytes(frameLength));
    }
}
測試代碼:
 
 @Test
    public void testFixedFrameDecoder(){
        EmbeddedChannel channel = new EmbeddedChannel(new FixedLengthFrameDecoder(4));
        //測試入站寫入
        ByteBuf buf = Unpooled.buffer();
        for(int i = 0; i < 10 ; i++)
            buf.writeByte(i);
        ByteBuf in = buf.duplicate();
        //入站寫入3個字節,此時 Decoder 會緩存這些數據,並沒有轉發這些數據到下一個 ChannelHandler
        assertFalse(channel.writeInbound(in.readBytes(3)));
        //入站寫入7個字節,加上之前寫入的3個字節,Decoder 轉發其中前8個字節,分爲2組轉發給下一個 ChannelHandler,剩餘2個字節仍被緩存
        assertTrue(channel.writeInbound(in.readBytes(7)));
        assertTrue(channel.finish());  //向通道發送結束信號
        //測試入站讀取
        //由上面的寫入過程可以估計,前2次都可以讀取到值,第3次讀取爲空值
        ByteBuf read = channel.readInbound();
        assertEquals(read,buf.readSlice(4));
        read.release();
        read = channel.readInbound();
        assertEquals(read,buf.readSlice(4));
        read.release();
        read = channel.readInbound();
        assertNull(read);
    }

出站處理器測試

以下測試一個入站編碼器 FixedLengthFrameDecoder;
FixedLengthFrameDecoder
 
 // 用於測試的 Encoder,將讀取的 Integer 絕對值化
public class AbsIntegerEncoder extends MessageToMessageEncoder<ByteBuf> {
    @Override
    protected void encode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        while(in.readableBytes() >= 4){
            int i = Math.abs(in.readInt());
            out.add(i);
        }
    }
}
測試代碼:
 
    @Test
    public void testAbsIntegerEncoder(){
        EmbeddedChannel channel = new EmbeddedChannel(new AbsIntegerEncoder());
        //測試出站寫入
        ByteBuf buf = Unpooled.buffer();
        for(int i = 0; i < 10; i++)
            buf.writeInt(i * -1);
        assertTrue(channel.writeOutbound(buf));
        assertTrue(channel.finish());
        //測試出站讀取
        for(int i = 0; i < 10; i++)
            assertEquals((Integer)i,channel.readOutbound());
        assertNull(channel.readOutbound());
    }

異常捕獲測試

拋出異常的處理器,FixedLengthFrameDecoder
 
public class FixedLengthFrameDecoder extends ByteToMessageDecoder {
    private final int frameLength;   //幀長度
    private final int maxFrameSize;  //最大幀長度
    public FixedLengthFrameDecoder(int frameLength) {
        this.frameLength = frameLength;
        this.maxFrameSize = 256;
    }
    public FixedLengthFrameDecoder(int frameLength, int maxFrameSize) {
        this.frameLength = frameLength;
        this.maxFrameSize = maxFrameSize;
    }
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        //過長幀異常
        if(in.readableBytes() >= maxFrameSize){
            in.clear();
            throw new TooLongFrameException();
        }
        //幀分割
        while(in.readableBytes() >= frameLength)
            out.add(in.readBytes(frameLength));
    }
}
測試代碼:
 
    @Test
    public void testFixedFrameDecoderException(){
        EmbeddedChannel channel = new EmbeddedChannel(new FixedLengthFrameDecoder(4,10));
        ByteBuf buf = Unpooled.buffer();
        for(int i = 0; i < 30; i++)
            buf.writeByte(i);
        try{
            channel.writeInbound(buf.duplicate());
            fail();
        }catch(TooLongFrameException e){
            e.printStackTrace();
        }
    }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章