jmockit中文网 dubbo bean

Dubbo是我们常用的RPC框架,在写单元测试需要调用Dubbo消费Bean时,如何模拟Dubbo消费Bean的行为呢?

   就拿发邮件来说,通常,在代码中,我们是调用邮件的Dubbo服务来完成发送邮件的目的,于是我们会在Spring配置好的发邮件的Dubbo消费Bean,
dubbo-consumer.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<? xml  version = "1.0"  encoding = "utf-8" ?>
< beans  xmlns = "http://www.springframework.org/schema/beans"
     xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
     xmlns:dubbo = "http://dubbo.apache.org/schema/dubbo"
     xsi:schemaLocation="http://www.springframework.org/schema/beans        
     http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        
     http://dubbo.apache.org/schema/dubbo        
     http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
 
     < dubbo:application  name = "consumer-of-dubbo-mock-test"  />
 
     < dubbo:registry  address = "zookeeper://your-zk-address:2181"  />
     <!-- 生成远程服务代理,可以和本地bean一样使用mailService -->
     < dubbo:reference  id = "mailService"  interface = "cn.jmockit.demos.MailService"  />
</ beans >

   熟悉Dubbo的朋友都知道,上面xml配置是Dubbo的基本配置,配置了dubbo服务的zookeeper地址,还配置了名叫mailService的Dubbo消费Bean,用于在应用程序中发送邮件。
 
   我们在运行单元测试时,如果zookeeper连不上或者mailService的服务提供者不存在,则会导致Spring初始化失败, 而且我们也不希望真正发送邮件(除非是为了测试发送邮件)。于是我们希望对mailService进行Mock。

  下面给出一种Mock Dubbo消费Bean的方案:

  1. 在spring初始化前,对所有Dubbo消费Bean的进行Mock,即<dubbo>标签里的interface都返回本地默认实现。

  2. 如果想对某几个Dubbo消费Bean进行Mock,则自定义Dubbo消费Bean的实现即可。



   请看测试代码:

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
//dubbo消费bean Mock 
@SuppressWarnings ({  "unchecked" "rawtypes"  })
@ContextConfiguration (locations = {  "/META-INF/dubbo-consumer.xml"  })
@RunWith (SpringJUnit4ClassRunner. class )
public  class  DubboConsumerBeanMockingTest {
     // 这里要@BeforeClass,因为要抢在spring加载dubbo前,对dubbo的消费工厂bean
     // ReferenceBean进行mock,不然dubbo可能因为连上不zk或无法找不
     // 服务的提供者等原因而无法初始化的,进而,单元测试运行不下去
     @BeforeClass
     public  static  void  mockDubbo() {
         // 你准备mock哪个消费bean
         // 比如要对dubbo-consumber.xml里配置的cn.jmockit.demos.MailService这个消费bean进行mock
         Map<String, Object> mockMap =  new  HashMap<String, Object>();
         mockMap.put( "cn.jmockit.demos.MailService" new  MockUp(MailService. class ) {
             // 在这里书写对这个消费bean进行mock的mock逻辑,想mock哪个方法,就自行添加,注意方法一定要加上@Mock注解哦
             @Mock
             public  boolean  sendMail( long  userId, String content) {
                 // 单元测试时,不需要调用邮件服务器发送邮件,这里统一mock邮件发送成功
                 return  true ;
             }
         }.getMockInstance());
         // 如果要Mock其它的消费bean,自行添加,mockMap.put.....如上
         new  DubboConsumerBeanMockUp(mockMap);
     }
 
     // 现在你使用的dubbo消费bean就是本地mock过的了,并不是指向远程dubbo服务的bean了
     @Resource
     MailService mailService;
 
     @Test
     public  void  testSendMail() {
         long  userId =  123456 ;
         String content =  "test mail content" ;
         Assert.isTrue(mailService.sendMail(userId, content));
     }
}

   上述代码,最关键的就是DubboConsumerBeanMockUp类了,这个类Mock了所有的Dubbo消费Bean.

   源代码如下:

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
//dubbo消费bean的MockUp(伪类)
@SuppressWarnings ( "rawtypes" )
public  class  DubboConsumerBeanMockUp  extends  MockUp<ReferenceBean> {
     // 自定义的消费bean mock对象
     private  Map<String, Object> mockMap;
 
     public  DubboConsumerBeanMockUp() {
     }
 
     public  DubboConsumerBeanMockUp(Map<String, Object> mockMap) {
         this .mockMap = mockMap;
     }
 
     // 对ReferenceBean的getObject方法的Mock
     @SuppressWarnings ( "unchecked" )
     @Mock
     public  Object getObject(Invocation inv)  throws  Exception {
         ReferenceBean ref = inv.getInvokedInstance();
         String interfaceName = ref.getInterface();
         Object mock = mockMap.get(interfaceName);
         if  (mock !=  null ) {
             return  mock;
         }
         return  ( new  MockUp(Class.forName(interfaceName)) {
         }).getMockInstance();
     }
}

© JMockit中文网 2018  打赏咖啡

猜你喜欢

转载自www.cnblogs.com/funkboy/p/12012551.html