ALL is Well!

          敏捷是一條很長(zhǎng)的路,摸索著前進(jìn)著

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            30 隨筆 :: 23 文章 :: 71 評(píng)論 :: 0 Trackbacks

          jMock用法簡(jiǎn)介

          總體上來(lái)說(shuō),jMock 是一個(gè)輕量級(jí)的模擬對(duì)象技術(shù)的實(shí)現(xiàn)。它具有以下特點(diǎn):
          1.可以用簡(jiǎn)單易行的方法定義模擬對(duì)象,無(wú)需破壞本來(lái)的代碼結(jié)構(gòu)表;
          2.可以定義對(duì)象之間的交互,從而增強(qiáng)測(cè)試的穩(wěn)定性;
          3.可以集成到測(cè)試框架;
          4.易擴(kuò)充;

          使用 jMock 模擬對(duì)象

          我們首先必須引入 jMock 的類,定義我們的測(cè)試類,創(chuàng)建一個(gè) Mockery 的對(duì)象用來(lái)代表上下文。上下文可以模擬出對(duì)象和對(duì)象的輸出,并且還可以檢測(cè)應(yīng)用是否合法。

           

          @SuppressWarnings("unchecked")
          public class BookListTest {
              
          private final Mockery context = new JUnit4Mockery() {
                  
          {
                      
          // 聲明針對(duì)類進(jìn)行mock,針對(duì)接口則會(huì)采用動(dòng)態(tài)代理,不需要聲明
                      setImposteriser(ClassImposteriser.INSTANCE);
                  }

              }
          ;
          }


          context 對(duì)象便可以用來(lái)創(chuàng)建Mock對(duì)象。
          接下來(lái)的例子,我們模擬一個(gè)ServiceCall對(duì)象,我們以它的Map call(String target, Map dataMap)為例,針對(duì)此方法,設(shè)定預(yù)期值。然后我們?cè)趫?zhí)行用例的時(shí)候調(diào)用此方法,便可以得到預(yù)期值。

          @SuppressWarnings("unchecked")
          public class BookListTest {
              
          private final Mockery context = new JUnit4Mockery() {
                  
          {
                      setImposteriser(ClassImposteriser.INSTANCE);
                  }

              }
          ;

              @Test
              
          public void testExecuteNormal() throws Exception {
                  
          final ServiceCall sCall = context.mock(ServiceCall.class);
                  context.checking(
          new Expectations() {
                      
          {
                          one(sCall).call(JMockService.queryDtlInfo, 
          null);
                          
          // 構(gòu)建預(yù)期結(jié)果
                          Map ret = new HashMap();
                          ret.put(
          "OrderId""9800000000");
                          ret.put(
          "Data"new ArrayList());
                          
          // 設(shè)定預(yù)期值
                          will(returnValue(ret));
                          
                          
          // 第二次被調(diào)用時(shí),返回null
                          one(sCall).call(JMockService.queryDtlInfo, new HashMap());
                          will(returnValue(
          null));
                      }

                  }
          );

                  BookList bListAction 
          = new BookList();
                  bListAction.setName(
          "jnbzwm");
                  
          // 設(shè)定ServiceCall對(duì)象為Mock對(duì)象
                  bListAction.setServiceCall(sCall);

                  
          // 執(zhí)行Action方法
                  bListAction.execute();

                  Assert.assertEquals(
          "9800000000", bListAction.getOrderId());
                  Assert.assertEquals(
          0, bListAction.getDataList().size());
              }



          校驗(yàn)expectations中的規(guī)則

          使用jMock時(shí),一般會(huì)通過(guò)如下代碼指定expectations:

          private final Mockery context = new JUnit4Mockery() {
                  
          {
                      setImposteriser(ClassImposteriser.INSTANCE);
                  }

              }
          ;

              @Test
              
          public void testExecuteNormal() throws Exception {
                  
          final ServiceCall sCall = context.mock(ServiceCall.class);
                  context.checking(
          new Expectations() {
                      
          {
                          one(sCall).call(JMockService.queryDtlInfo, 
          null);
                          
          // 構(gòu)建預(yù)期結(jié)果
                          Map ret = new HashMap();
                          ret.put(
          "OrderId""9800000000");
                          ret.put(
          "Data"new ArrayList());
                          
          // 設(shè)定預(yù)期值
                          will(returnValue(ret));
                          
                          
          // 第二次被調(diào)用時(shí),返回null
                          one(sCall).call(JMockService.queryDtlInfo, new HashMap());
                          will(returnValue(
          null));
                      }

                  }
          );
                  .
              }

          }

          為了校驗(yàn)expectations中的規(guī)則是否都滿足,可以在測(cè)試完成后通過(guò)增加 context.assertIsSatisfied()方法來(lái)驗(yàn)證expectations是否滿足。
          如下代碼:

              @Test
              
          public void testExecuteNormal() throws Exception {
                  
          final ServiceCall sCall = context.mock(ServiceCall.class);
                  context.checking(
          new Expectations() {
                      
          {
                          one(sCall).call(JMockService.queryDtlInfo, 
          null);
                          
          // 構(gòu)建預(yù)期結(jié)果
                          Map ret = new HashMap();
                          ret.put(
          "OrderId""9800000000");
                          ret.put(
          "Data"new ArrayList());
                          
          // 設(shè)定預(yù)期值
                          will(returnValue(ret));
                          
                          
          // 第二次被調(diào)用時(shí),返回null
                          one(sCall).call(JMockService.queryDtlInfo, new HashMap());
                          will(returnValue(
          null));
                      }

                  }
          );

                  BookList bListAction 
          = new BookList();
                  bListAction.setName(
          "jnbzwm");
                  
          // 設(shè)定ServiceCall對(duì)象為Mock對(duì)象
                  bListAction.setUpfServiceCall(sCall);

                  
          // 執(zhí)行Action方法
                  bListAction.execute();

                  Assert.assertEquals(
          "9800000000", bListAction.getOrderId());
                  Assert.assertEquals(
          0, bListAction.getDataList().size());
                  context.assertIsSatisfied(); 
              }

          由于我定義了兩條規(guī)則,而第二條并未調(diào)用,所以此用例不會(huì)通過(guò)。

          同一個(gè)方法連續(xù)調(diào)用時(shí)返回不同的值

          有兩種方法,第一種就是直接通過(guò)多次調(diào)用 will(returnValue(X))來(lái)指定。如:

              @Test
              
          public void testExecuteNormal() throws Exception {
                  
          final ServiceCall sCall = context.mock(ServiceCall.class);
                  context.checking(
          new Expectations() {
                      
          {
                          one(sCall).call(JMockService.queryDtlInfo, 
          null);
                          will(returnValue(
          0));

                          
          // 第二次被調(diào)用時(shí),返回1
                          one(sCall).call(JMockService.queryDtlInfo, null);
                          will(returnValue(
          1));

                          
          // 第三次被調(diào)用時(shí),返回2
                          one(sCall).call(JMockService.queryDtlInfo, null);
                          will(returnValue(
          2));
                      }

                  }
          );
                  
              }

          然而第一種方法會(huì)增加維護(hù)成本,且缺乏可控性。jMock提供了第二種方法,即通過(guò)onConsecutiveCalls的action來(lái)實(shí)現(xiàn)返回不同的返回值。如:

           

              @Test
              
          public void testExecuteNormal() throws Exception {
                  
          final ServiceCall sCall = context.mock(ServiceCall.class);
                  context.checking(
          new Expectations() {
                      
          {
                          atLeast(
          1).of (sCall).call(JMockService.queryDtlInfo, null);
                          will(onConsecutiveCalls( returnValue(
          0),  returnValue(1),  returnValue(2))); 
                      }

                  }
          );
                  
              }



          指定mock的方法拋出異常

          在will方法中直接使用throwException的action。參考如下語(yǔ)法:

          one(sCall).call(JMockService.queryDtlInfo, null);
          // 設(shè)定預(yù)期值,拋出異常
          will(throwException(new BusinessException("~", "name can't empty.")));
          

          結(jié)合測(cè)試異常一起使用,代碼如下:

              @Test(expected=BusinessException.class)
              
          public void testExecuteNormal() throws Exception {
                  
          final ServiceCall sCall = context.mock(ServiceCall.class);
                  context.checking(
          new Expectations() {
                      
          {
                          one(sCall).call(JMockService.queryDtlInfo, 
          null);
                          
          // 構(gòu)建預(yù)期結(jié)果
                          Map ret = new HashMap();
                          ret.put(
          "OrderId""9800000000");
                          ret.put(
          "Data"new ArrayList());
                          
          // 設(shè)定預(yù)期值
                          will(throwException(new BusinessException("~""name can't empty.")));

                          
          // 第二次被調(diào)用時(shí),返回null
                          one(sCall).call(JMockService.queryDtlInfo, new HashMap());
                          will(returnValue(
          null));
                      }

                  }
          );

                  BookList bListAction 
          = new BookList();
                  bListAction.setName(
          "");
                  
          // 設(shè)定ServiceCall對(duì)象為Mock對(duì)象
                  bListAction.setUpfServiceCall(sCall);

                  
          // 執(zhí)行Action方法
                  bListAction.execute();
              }


          posted on 2010-12-17 09:28 李 明 閱讀(12086) 評(píng)論(3)  編輯  收藏 所屬分類: JUnit

          評(píng)論

          # Nike Air Jordan 2010-12-17 10:16 Nike Air Jordan
          看得迷迷糊糊的  回復(fù)  更多評(píng)論
            

          # re: JUnit單元測(cè)試Mock技術(shù)之jMock用法介紹 2010-12-17 10:59 Ronaldo
          @Nike Air Jordan
          怎么迷糊了?  回復(fù)  更多評(píng)論
            

          # re: JUnit單元測(cè)試Mock技術(shù)之jMock用法介紹 2016-07-18 15:14 pjl
          JMockService是啥?  回復(fù)  更多評(píng)論
            


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 嘉荫县| 上蔡县| 大城县| 靖安县| 汤原县| 宝清县| 双桥区| 遵化市| 克东县| 珲春市| 什邡市| 钦州市| 揭阳市| 奉新县| 抚顺县| 闸北区| 博客| 正定县| 绥化市| 刚察县| 彭山县| 南城县| 北宁市| 镇平县| 浮山县| 长沙县| 元朗区| 香格里拉县| 汉川市| 正定县| 繁昌县| 华蓥市| 麦盖提县| 宁德市| 兰州市| 台东县| 彰化县| 桓仁| 云安县| 安仁县| 海宁市|