Unit test of Netty Combat nine

Source: Internet
Author: User

Channelhandler is a key element of the Netty application, so thoroughly testing them should be a standard part of your development process. Best practices require that your tests not only prove that your implementation is correct, but also make it easy to isolate problems that suddenly arise as a result of code changes. This type of test is called unit testing.

The basic idea is to test your code in as small a chunk as possible, and isolate it as much as possible from other code modules and runtime dependencies.

1. Embeddedchannel Overview

As you already know, you can connect the Channelhandler implementations in Channelpipeline to build the business logic of your application. As explained earlier, this design supports the decomposition of any potentially complex process into small reusable components, each of which will handle a well-defined task or step.

Netty provides its so-called embedded transmission, which is used to test the Channelhandler. This transmission is a special channel to realize the function of--embeddedchannel--. This is an easy way to implement the propagation of events through Channelpipeline.

The idea is straightforward: write inbound or outbound data to Embeddedchannel and check to see if anything has reached the end of the channelpipeline. In this way, you can determine whether the message has been encoded or decoded, and whether any channelhandler actions have been triggered.

Shows how the data flows through the channelpipeline using the Embeddedchannel method. You can use the Writeoutbound () method to write messages to the channel and pass Channelpipeline along the outbound direction. You can then use the Readoutbound () method to read a message that has been processed and determine whether the result is the same as expected. Similarly, for inbound data, you need to use the Writeinbound () and Readinbound () methods.

In each case, the message will pass through the channelpipeline and be handled by the associated Channelinboundhandler or Channeloutboundhandler. If the messages are not consumed, then you can use the Readinbound () or Readoutbound () method to read them out of the channel, as appropriate, after the messages have been processed.

2, use Embeddedchannel test Channelhandler

JUnit Assertion

The Org.junit.Assert class provides a number of static methods for testing. A failed assertion will cause an exception to be thrown, and the test that is currently executing will be terminated. The most efficient way to import these assertions is through an import static statement:

Import static org.junit.assert.*;

Once this is done, you can call the Assert method directly:

Assertequals (Buf.readslice (3), read);

3. Test inbound messages

Shows a simple bytetomessagedecoder implementation. Given enough data, this implementation produces a fixed-size frame. If there is not enough data to read, it waits for the next chunk to arrive and checks again to see if a new frame is generated. As you can see on the right side of the frame, this particular decoder produces frames that are fixed to a size of 3 bytes. Therefore, it may require multiple events to provide enough bytes to produce a single frame.

Eventually, each frame is passed to the next channelhandler in Channelpipeline, and the implementation of the decoder is shown in the following code.

Extend Bytetomessagedecoder to process inbound bytes and decode them as message publicClassFixedlengthframedecoderExtendsbytetomessagedecoder{Privatefinal int framelength;Specifies the length of the frame to be generated publicFixedlengthframedecoder (int framelength)Throwsillegalaccessexception {if (Framelength <=0) {Thrownew illegalaccessexception ( " Framelength must be a positive integer: "+ framelength);} this.framelength = framelength;}  @Override protected void decode ( Channelhandlercontext Channelhandlercontext, bytebuf bytebuf, List <object> list) throws Exception { //check if there are enough bytes to be read to generate the next frame while (Bytebuf.readablebytes () >= framelength) {//read a new frame from bytebuf bytebuf buf = Bytebuf.readbytes (framelength); //adds the frame to the list of messages that have been decoded list.add (BUF);} }} 

The following code shows a test for the previous code using Embeddedchannel

public class Fixedlengthframedecodertest {@TestPublicvoid Decode () throws Exception {Create a bytebuf, and store 9 bytes bytebuf buf = unpooled.Buffer ();for (int i =0; I <9; i++) {buf.writebyte (i);} Bytebuf input = Buf.duplicate ();//Create a Embeddedchannel and add a fixedlengthframedecoder that will be tested with a 3-byte frame length Embeddedchannel Channel = new embeddedchannel (new Fixedlengthframedecoder ( Span class= "Hljs-number" >3)); //write bytes //writes data to Embeddedchannel Asserttrue ( Channel.writeinbound (Input.retain ())); //mark Channel as Completed status Asserttrue (Channel.finish ()); //read messages //read the generated message and verify that there are 3 frames, where each frame is 3 bytes bytebuf read = (bytebuf) channel.readinbound (); Assertequals (Buf.readslice (3), read); read. release (); Assertnull (Channel.readinbound ()); buf. release ()}}            

4. Test the outbound message

Simply mentioning the processor--absintegerencoder we are testing, it is a specialized implementation of the Netty Messagetomessageencoder that converts a negative integer to an absolute value.

The example will work in the following ways:

--The Embeddedchannel holding Absintegerencoder will write the station data in the form of a 4-byte negative integer.

--The encoder will read each negative integer from the incoming bytebuf and will call the Math.Abs () method to get its absolute value

--The encoder will write the absolute value of each negative integer into the channelpipeline. The following code implements this logic.

Publicclass absintegerencoder extends messagetomessageencoder<bytebuf>{ @Override protected void Encode (channelhandlercontext Channelhandlercontext, bytebuf bytebuf, List< object> list) throws exception {//check if there are enough bytes to encode while (bytebuf.readablebytes () >= 4) { //reads the next integer from the input bytebuf, and calculates its absolute value int value = math.abs ( Bytebuf.readint ()); //writes the integer to the list of encoded messages List.add (value);} }} 

The following code uses Embeddedchannel to test the code

PublicClassabsintegerencodertest {@TestPublicvoidEncode()Throws Exception {Create a bytebuf, and write 9 negative integers bytebuf buf = Unpooled.buffer ();For (int i = 1; i < i++) {buf.writeint (i *-1);} //Create a Embeddedchannel and install a absintegerencoder to test embeddedchannel channel = new Embeddedchannel ( new Absintegerencoder ()); //write bytebuf, and assert that calling the Readoutbound () method will result in data asserttrue (Channel.writeoutbound (BUF)); Asserttrue (Channel.finish ()) ; //Read the resulting message and assert that they contain the corresponding absolute value //read bytes for (int i=1; i < ; i++) {assertequals (I, Channe L.readoutbound ()); } assertnull (Channel.readoutbound ()); }}

5. Test exception Handling

Applications often need to perform tasks that are more complex than transforming data. For example, you might need to handle malformed input or excessive data. In the next example, if the number of bytes read exceeds a certain limit, we will throw a toolongframeexception. This is a method that is often used to prevent resources from being exhausted.

For example, the maximum frame size has been set to 3 bytes, and if the size of a frame exceeds that limit, then the program will discard its bytes and throw a toolongframeexception. Other Channelhandler in Channelpipeline can choose to handle the exception in the Exceptioncaught () method or ignore it. Its implementation is shown in the following code.

PublicClassFramechunkdecoderExtendsbytetomessagedecoder{Private finalint maxframesize;PublicFramechunkdecoder (int maxframesize) {This.maxframesize = MaxFrameSize; } @OverrideProtectedvoid decode (ChannelHandlerContext Channelhandlercontext, Bytebuf in, list<object> out) Throws Exception {int readablebytes = in.readablebytes (); Span class= "Hljs-comment" >//if the frame is too large, discard it and throw an exception if (Readablebytes > MaxFrameSize) {//discard the bytes in.clear (); throw new toolongframeexception ();} //read a new frame from bytebuf bytebuf buf = in.readbytes (readableBytes) ; //add the frame to the list of decoded messages out. Add (BUF); }} 

The Try/catch block used is a special feature of the Embeddedchannel. If one of the write* methods produces a checked exception, it will be wrapped in a runtimeexception and thrown, making it easy to test whether a exception has been processed in the process of processing the data.

Unit test of Netty Combat nine

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.