基于Netty的RPC简单框架实现(五):功能测试与性能测试

释放双眼,带上耳机,听听看~!

1.
JUnit依赖

功能测试使用到了JUnit


1
2
3
4
5
6
1<dependency>
2       <groupId>junit</groupId>
3       <artifactId>junit</artifactId>
4       <version>4.12</version>
5</dependency>
6

1
2
1在pom.xml中添加上方的依赖
2

2.测试前准备

(1).定义接口JUnitTestInterface


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1package com.maigo.rpc.test;
2
3import java.util.List;
4
5public interface JUnitTestInterface
6{
7   public String methodWithoutArg();
8   public String methodWithArgs(String arg1, int arg2);
9   public JUnitTestCustomObject methodWithCustomObject(JUnitTestCustomObject customObject);
10  public List<String> methodReturnList(String arg1, String arg2);
11  public void methodThrowException();
12  public void methodTimeOut();
13  public void methodReturnVoid();
14  public String methodDelayOneSecond();
15  public int methodForMultiThread(int threadId);
16  public String methodForPerformance();
17}
18

定义了用于测试的方法

(2).实现接口JUnitTestInterface


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
1package com.maigo.rpc.test;
2
3import java.util.Arrays;
4import java.util.List;
5
6public class JUnitTestInterfaceImpl implements JUnitTestInterface
7{
8   public String methodWithoutArg()
9   {
10      return "this is return from methodWithoutArg()";
11  }
12
13  public String methodWithArgs(String arg1, int arg2)
14  {
15      return arg1 + " = " + arg2;
16  }
17
18  public JUnitTestCustomObject methodWithCustomObject(
19          JUnitTestCustomObject customObject)
20  {
21      JUnitTestCustomObject object = new JUnitTestCustomObject(customObject.getString() + " after",
22              customObject.getI() + 47);
23      return object;
24  }
25
26  public List<String> methodReturnList(String arg1, String arg2)
27  {
28      return Arrays.asList(arg1, arg2);
29  }
30
31  public void methodThrowException()
32  {
33      throw new JUnitTestCustomException();
34  }
35
36  public void methodTimeOut()
37  {
38      try
39      {
40          Thread.sleep(5000);
41      }
42      catch (InterruptedException e)
43      {
44          e.printStackTrace();
45      }
46  }
47
48  public void methodReturnVoid()
49  {
50      return;
51  }
52
53  public String methodDelayOneSecond()
54  {
55      try
56      {
57          Thread.sleep(1000);
58      }
59      catch (InterruptedException e)
60      {
61          e.printStackTrace();
62      }
63     
64      return "I have sleep 1000ms already.";
65  }
66
67  public int methodForMultiThread(int threadId)
68  {      
69      return threadId;
70  }
71
72  public String methodForPerformance()
73  {
74      return "Maigo";
75  }
76}
77
78

1
2
1实现了用于测试的方法  
2

(3).定义自定义类型JUnitTestCustomObject


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1package com.maigo.rpc.test;
2
3public class JUnitTestCustomObject
4{
5   private String string;
6   private int i;
7      
8   public JUnitTestCustomObject(String string, int i)
9   {
10      super();
11      this.string = string;
12      this.i = i;
13  }
14 
15  public String getString()
16  {
17      return string;
18  }
19
20  public void setString(String string)
21  {
22      this.string = string;
23  }
24
25  public int getI()
26  {
27      return i;
28  }
29
30  public void setI(int i)
31  {
32      this.i = i;
33  }
34
35  @Override
36  public boolean equals(Object obj)
37  {
38      JUnitTestCustomObject object = null;
39      if(obj instanceof JUnitTestCustomObject)
40          object = (JUnitTestCustomObject)obj;
41      else
42          return false;
43     
44      return (this.string.equals(object.string)) && (this.i == object.i);
45  }
46}
47

1
2
1  **(4).定义自定义异常JUnitTestCustomException**
2

1
2
3
4
5
6
7
8
9
10
11
12
1package com.maigo.rpc.test;
2
3public class JUnitTestCustomException extends RuntimeException
4{
5   private static final long serialVersionUID = 591530421634999576L;
6
7   public JUnitTestCustomException()
8   {
9       super("CustomException");
10  }
11}
12

1
2
1  **3.功能测试  
2

(1).JUnitServerTest**


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1package com.maigo.rpc.test;
2
3import static org.junit.Assert.*;
4
5import org.junit.Test;
6
7import com.maigo.rpc.server.RpcServer;
8import com.maigo.rpc.server.RpcServerBuilder;
9
10public class JUnitServerTest
11{
12  @Test
13  public void testServerStart()
14  {
15      JUnitTestInterfaceImpl jUnitTestInterfaceImpl = new JUnitTestInterfaceImpl();
16      RpcServer rpcServer = RpcServerBuilder.create()
17                .serviceInterface(JUnitTestInterface.class)
18                .serviceProvider(jUnitTestInterfaceImpl)
19                .threads(4)
20                .bind(3721)
21                .build();
22      rpcServer.start();
23  }
24 
25  public static void main(String[] args)
26  {
27      new JUnitServerTest().testServerStart();
28  }
29}
30

测试结果:

正常启动RPC服务器(维持服务器开启状态,后续功能测试和性能测试需要服务器在线)

(2).JUnitFunctionTest


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
1package com.maigo.rpc.test;
2
3import static org.junit.Assert.*;
4
5import java.util.List;
6import java.util.concurrent.CountDownLatch;
7import java.util.concurrent.TimeUnit;
8
9import org.junit.BeforeClass;
10import org.junit.Test;
11
12import com.maigo.rpc.aop.RpcInvokeHook;
13import com.maigo.rpc.client.RpcClientAsyncProxy;
14import com.maigo.rpc.client.RpcClientProxyBuilder;
15import com.maigo.rpc.exception.RpcMethodNotFoundException;
16import com.maigo.rpc.exception.RpcTimeoutException;
17import com.maigo.rpc.future.RpcFuture;
18import com.maigo.rpc.future.RpcFutureListener;
19
20public class JUnitFunctionTest
21{
22  /**
23   * use for sync-mode test
24   */
25  public static JUnitTestInterface jUnitTestInterface;
26 
27  /**
28   * use for async-mode test
29   */
30  public static RpcClientAsyncProxy rpcClientAsyncProxy;
31 
32  private static int integerBeforeHook = 0;
33  private static int integerAfterHook = 0;
34  private CountDownLatch countDownLatch;
35 
36  @BeforeClass
37  public static void init()
38  {
39      RpcInvokeHook hook = new RpcInvokeHook()
40      {          
41          public void beforeInvoke(String methodName, Object[] args)
42          {
43              integerBeforeHook++;
44          }
45         
46          public void afterInvoke(String methodName, Object[] args)
47          {
48              integerAfterHook++;
49          }
50      };
51     
52      jUnitTestInterface = RpcClientProxyBuilder.create(JUnitTestInterface.class)
53                                              .timeout(2000)
54                                              .threads(4)
55                                              .hook(hook)
56                                              .connect("127.0.0.1", 3721)
57                                              .build();
58     
59      rpcClientAsyncProxy = RpcClientProxyBuilder.create(JUnitTestInterface.class)
60                                              .timeout(2000)
61                                              .threads(4)
62                                              .hook(hook)
63                                              .connect("127.0.0.1", 3721)
64                                              .buildAsyncProxy();
65  }
66 
67  @Test
68  public void testMethodWithoutArg()
69  {
70      assertEquals("this is return from methodWithoutArg()",
71              jUnitTestInterface.methodWithoutArg());
72  }
73 
74  @Test
75  public void testMethodWithArgs()
76  {
77      assertEquals("age = 23", jUnitTestInterface.methodWithArgs("age", 23));
78      assertEquals("born = 1992", jUnitTestInterface.methodWithArgs("born", 1992));
79  }
80 
81  @Test
82  public void methodWithCustomObject()
83  {
84      JUnitTestCustomObject beforeCustomObject = new JUnitTestCustomObject("before", 3);
85      JUnitTestCustomObject afterCustomObject =
86              jUnitTestInterface.methodWithCustomObject(beforeCustomObject);
87      assertEquals("before after", afterCustomObject.getString());
88      assertEquals(50, afterCustomObject.getI());
89  }
90 
91  @Test
92  public void testMethodReturnList()
93  {
94      List<String> list = jUnitTestInterface.methodReturnList("hello", "world");
95      assertEquals("hello", list.get(0));
96      assertEquals("world", list.get(1));
97  }
98 
99  @Test(expected=JUnitTestCustomException.class)
100 public void testMethodThrowException()
101 {
102     jUnitTestInterface.methodThrowException(); 
103 }
104
105 @Test(expected=RpcTimeoutException.class)
106 public void testMethodTimeOut()
107 {
108     jUnitTestInterface.methodTimeOut();
109 }
110
111 @Test
112 public void testMethodReturnVoid()
113 {
114     jUnitTestInterface.methodReturnVoid();
115 }
116
117 @Test
118 public void testMethodHook()
119 {
120     integerBeforeHook = 100;
121     integerAfterHook = 500;
122     jUnitTestInterface.methodWithoutArg();
123     assertEquals(101, integerBeforeHook);
124     assertEquals(501, integerAfterHook);
125 }
126
127 @Test
128 public void testFutureSuccess()
129 {
130     RpcFuture rpcFuture = rpcClientAsyncProxy.call("methodDelayOneSecond");
131     assertNotNull(rpcFuture);
132     assertFalse(rpcFuture.isDone());
133    
134     try
135     {
136         Thread.sleep(2000);
137     }
138     catch (InterruptedException e)
139     {
140         e.printStackTrace();
141     }
142    
143     assertTrue(rpcFuture.isDone());
144     try
145     {
146         assertEquals("I have sleep 1000ms already.", rpcFuture.get());
147     }
148     catch (Throwable e)
149     {
150         e.printStackTrace();
151     }
152 }
153
154 @Test
155 public void testFutureError()
156 {
157     RpcFuture rpcFuture = rpcClientAsyncProxy.call("methodThrowException");
158     assertNotNull(rpcFuture);  
159     try
160     {
161         rpcFuture.get();
162     }
163     catch (Throwable e)
164     {
165         if(e instanceof JUnitTestCustomException)
166             return;
167        
168         fail(e + " was caught when testFutureError.");
169     }
170    
171     fail("failed to catch JUnitTestCustomException.");
172 }
173
174 @Test
175 public void testFutureListener()
176 {
177     //1.test for get a result by RpcFutureListener
178     countDownLatch = new CountDownLatch(1);
179    
180     RpcFuture rpcFuture = rpcClientAsyncProxy.call("methodDelayOneSecond");
181     assertNotNull(rpcFuture);
182     rpcFuture.setRpcFutureListener(new RpcFutureListener()
183     {          
184         public void onResult(Object result)
185         {
186             countDownLatch.countDown();
187         }
188        
189         public void onException(Throwable throwable)
190         {
191             fail(throwable + " was caught when testFutureListener.");
192         }
193     });
194    
195     try
196     {
197         if(!countDownLatch.await(2000, TimeUnit.MILLISECONDS))
198             fail("failed to get result by RpcFutureListener.");
199     }
200     catch (InterruptedException e)
201     {
202         fail(e + " was caught when testFutureListener.");
203     }
204    
205    
206     //2.test for get a exception by RpcFutureListener
207     countDownLatch = new CountDownLatch(1);
208     rpcFuture = rpcClientAsyncProxy.call("methodThrowException");
209     assertNotNull(rpcFuture);
210     rpcFuture.setRpcFutureListener(new RpcFutureListener()
211     {          
212         public void onResult(Object result)
213         {
214             fail("failed to catch JUnitTestCustomException.");           
215         }
216        
217         public void onException(Throwable throwable)
218         {
219             if(throwable instanceof JUnitTestCustomException)
220                 countDownLatch.countDown();
221             else
222                 fail("failed to catch JUnitTestCustomException.");
223         }
224     });
225    
226     try
227     {
228         if(!countDownLatch.await(1000, TimeUnit.MILLISECONDS))
229             fail("failed to get exception by RpcFutureListener.");
230     }
231     catch (InterruptedException e)
232     {
233         fail(e + " was caught when testFutureListener.");
234     }
235 }
236
237 @Test(expected=RpcMethodNotFoundException.class)
238 public void testMethodNotFound()
239 {
240     rpcClientAsyncProxy.call("methodWhichIsNotExist");
241 }
242}
243

1
2
1代码量较大,但都简单易懂,对每个方法调用后加上断言判断结果是否符合预期。其中包含了对同步方式和异步方式的测试,异步方式中对RpcFuture和RpcFutureListener也进行了测试。测试的内容包括0个或多个参数,使用自定义类型的参数,返回自定义类型的参数,返回List<T>,方法抛出异常,方法调用超时,方法返回空类型,设置的钩子函数Hook的调用等。由于同步方式直接调用实现了接口的代理对象的方法,不存在找不到方法的情况。而异步方式下使用call()方法进行调用,有可能存在找不到与参数1同名的方法的情况,此时会抛出RpcMethodNotFoundException,因此异步方式下还应对此情景进行测试。因此此功能测试基本涵盖本框架使用的方方面面。
2

测试结果:

测试全部通过

(3).JUnitMultiThreadSafeTest

为验证RPC客户端是否是线程安全的,进行线程安全测试


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
1package com.maigo.rpc.test;
2
3import static org.junit.Assert.*;
4
5import java.util.concurrent.CountDownLatch;
6import java.util.concurrent.ExecutorService;
7import java.util.concurrent.Executors;
8import java.util.concurrent.TimeUnit;
9
10import org.junit.BeforeClass;
11import org.junit.Test;
12
13import com.maigo.rpc.client.RpcClientProxyBuilder;
14
15public class JUnitMultiThreadSafeTest
16{
17  public static JUnitTestInterface jUnitTestInterface;
18  public final static int THREADS = 20;
19  public final static int INVOKES = 1000;
20  public final static int TIMEOUT = 10000;
21 
22  @BeforeClass
23  public static void init()
24  {
25      jUnitTestInterface = RpcClientProxyBuilder.create(JUnitTestInterface.class)
26              .timeout(2000)
27              .threads(4)
28              .connect("127.0.0.1", 3721)
29              .build();
30  }
31
32  @Test
33  public void testMultiThreadSafe()
34  {
35      ExecutorService threadPool = Executors.newFixedThreadPool(THREADS);
36      CountDownLatch countDownLatch = new CountDownLatch(THREADS * INVOKES);
37      for(int i=0; i<THREADS; i++)
38      {
39          threadPool.execute(new JUnitMultiThreadSafeTestThread(i, jUnitTestInterface, countDownLatch));
40      }
41     
42      try
43      {
44          if(countDownLatch.await(TIMEOUT, TimeUnit.MILLISECONDS))
45              return;
46          else
47              fail("some thread did not finish all the invoke.");
48      }
49      catch (InterruptedException e)
50      {
51          e.printStackTrace();
52      }
53  }
54
55  private static class JUnitMultiThreadSafeTestThread extends Thread
56  {
57      private int threadId;
58      private JUnitTestInterface jUnitTestInterface;
59      private CountDownLatch countDownLatch;
60     
61      public JUnitMultiThreadSafeTestThread(int threadId, JUnitTestInterface jUnitTestInterface,
62              CountDownLatch countDownLatch)
63      {
64          this.threadId = threadId;
65          this.jUnitTestInterface = jUnitTestInterface;
66          this.countDownLatch = countDownLatch;
67      }
68     
69      @Override
70      public void run()
71      {
72          for(int i=0; i<INVOKES; i++)
73          {
74              int result = jUnitTestInterface.methodForMultiThread(threadId);
75              if(result == threadId)
76                  countDownLatch.countDown();
77          }
78      }
79  }
80}
81

1
2
1开启了20个线程使用共享的RpcClient代理对象jUnitTestInterface各进行1000次方法调用。每个线程拥有唯一的线程Id,所调用的方法会直接返回其参数,每个线程中对methodForMultiThread()方法的调用送进本线程的Id,当且仅当methodForMultiThread()方法的返回值等于本线程Id才会让countDownLatch减1。每个线程只会进行1000次调用,故若由于线程不安全导致某次调用失败或调用结果被错误的线程获取到,countDownLatch就不可能递减至0了,此时测试将不通过。而若RPC客户端是线程安全的,则countDownLatch能顺利递减至0,测试通过。
2

测试结果:

测试通过

(4).RpcPerformanceTest


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
1package com.maigo.rpc.test;
2
3import java.util.concurrent.CountDownLatch;
4import java.util.concurrent.ExecutorService;
5import java.util.concurrent.Executors;
6import java.util.concurrent.TimeUnit;
7
8import com.maigo.rpc.client.RpcClientProxyBuilder;
9import com.maigo.rpc.utils.InfoPrinter;
10
11public class RpcPerformanceTest
12{
13  public static JUnitTestInterface jUnitTestInterface;
14  public final static int THREADS = 16;
15  public final static int INVOKES = 10000;
16  public final static int TIMEOUT = 300;
17     
18  public static void main(String[] args) throws Exception
19  {
20      jUnitTestInterface = RpcClientProxyBuilder.create(JUnitTestInterface.class)
21              .timeout(0)
22              .threads(4)
23              .connect("127.0.0.1", 3721)
24              .build();
25     
26      ExecutorService threadPool = Executors.newFixedThreadPool(THREADS);
27      CountDownLatch countDownLatch = new CountDownLatch(THREADS * INVOKES);
28      InfoPrinter.println("RpcPerformanceTest started.");
29      long startTime = System.currentTimeMillis();
30      for(int i=0; i<THREADS; i++)
31      {
32          threadPool.execute(new RpcPerformanceTestThread(jUnitTestInterface, countDownLatch));
33      }
34     
35      if(countDownLatch.await(TIMEOUT, TimeUnit.SECONDS))
36      {
37          long endTime = System.currentTimeMillis();
38          double tps = THREADS * INVOKES / ((endTime - startTime) / 1000f);
39          InfoPrinter.println("RpcPerformanceTest finished.");
40          InfoPrinter.println("Result tps = " + tps);          
41      }
42      else
43      {
44          InfoPrinter.println("RpcPerformanceTest failed.");           
45      }
46  }
47 
48  private static class RpcPerformanceTestThread extends Thread
49  {
50      private JUnitTestInterface jUnitTestInterface;
51      private CountDownLatch countDownLatch;
52     
53      public RpcPerformanceTestThread(JUnitTestInterface jUnitTestInterface,
54              CountDownLatch countDownLatch)
55      {
56          this.jUnitTestInterface = jUnitTestInterface;
57          this.countDownLatch = countDownLatch;
58      }
59     
60      @Override
61      public void run()
62      {
63          for(int i=0; i<INVOKES; i++)
64          {
65              jUnitTestInterface.methodForPerformance();
66              countDownLatch.countDown();
67          }
68      }
69  }
70}
71

1
2
1开启了16个线程,每个线程进行10000次方法调用。调用结束用调用总数160000除以耗费的时间即可得到每秒处理的调用请求数。
2

测试结果:
测试环境:酷睿i5-2410m  4G内存  64位Windows7操作系统


1
2
3
4
5
6
1[2015-09-21 23:40:05]:Try to connect to [127.0.0.1:3721].
2[2015-09-21 23:40:05]:Connect to [127.0.0.1:3721] successed.
3[2015-09-21 23:40:05]:RpcPerformanceTest started.
4[2015-09-21 23:40:14]:RpcPerformanceTest finished.
5[2015-09-21 23:40:14]:Result tps = 16872.298828125
6

完整的代码提交在:https://github.com/maigo-uestc/Maigo-RPC 

给TA打赏
共{{data.count}}人
人已打赏
安全经验

google adsense作弊及反作弊技术分析

2021-10-11 16:36:11

安全经验

安全咨询服务

2022-1-12 14:11:49

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索