Sky's blog

          我和我追逐的夢(mèng)

          常用鏈接

          統(tǒng)計(jì)

          其他鏈接

          友情鏈接

          最新評(píng)論

          easymock教程-strict和nice

              在easymock的使用過(guò)程中,當(dāng)創(chuàng)建mock對(duì)象時(shí),我們會(huì)遇到 strict mock和nice mock的概念。

              比如創(chuàng)建mock對(duì)象我們通常使用EasyMock.createMock(),但是我們會(huì)發(fā)現(xiàn)easymock同時(shí)提供了兩個(gè)類似的方法:

           EasyMock.createNiceMock()
           EasyMock.createStrictMock()

              類似的在創(chuàng)建MocksControl時(shí),除了通常的EasyMock.createControl() 外,easymock也同時(shí)提供兩個(gè)類似的方法:

           EasyMock.createNiceControl() 
           EasyMock.createStrictControl() 

              我們來(lái)看看strict和nice有什么作用。參考easymock的javadoc,我們對(duì)比createMock()和createStrictMock():
           EasyMock.createMock():          Creates a mock object that implements the given interface, order checking is disabled by default.
           EasyMock.createNiceMock() : Creates a mock object that implements the given interface, order checking is enabled by default.

              發(fā)現(xiàn)strict mock方式下默認(rèn)是開(kāi)啟調(diào)用順序檢測(cè)的,而普通的mock方式則默認(rèn)不開(kāi)啟調(diào)用順序檢測(cè)。

              再看一下createNiceMock():

          Creates a mock object that implements the given interface, order checking is disabled by default, and the mock object will return 0, null or false for unexpected invocations.

              和createMock()相同的是默認(rèn)不開(kāi)啟調(diào)用順序檢測(cè),另外有一個(gè)非常有用的功能就是對(duì)于意料之外的調(diào)用將返回0,null 或者false.之所以說(shuō)有用,是因?yàn)樵谖覀兊膶?shí)際開(kāi)發(fā)過(guò)程中,有時(shí)候會(huì)有這樣的需求:對(duì)于某個(gè)mock對(duì)象的調(diào)用(可以是部分,也可以是全部),我們完全不介意調(diào)用細(xì)節(jié),包括是否調(diào)用和調(diào)用順序,參數(shù),返回值,我們只要求mock對(duì)象容許程序可以繼續(xù)而不是拋出異常報(bào)告說(shuō) unexpected invocations 。nice mock在這種情況下可以為我們節(jié)省大量的工作量,非常方便。

              我們來(lái)看一個(gè)簡(jiǎn)單的實(shí)際使用的例子,假設(shè)我們有一個(gè)Business類,依賴于兩個(gè)service 接口:

              先看只調(diào)用一個(gè)依賴的情況,注意在record階段service1.method2()和service1.method1()的順序和business.executeService1()方法中的實(shí)際調(diào)用順序是故意設(shè)置為不同的。

              public class Business {
                  
          private Service1 service1;

                  
          private Service2 service2;
                  
                  
          public void executeService1() {
                      service1.method1();
                      service1.method2();
                  }

                  
                  
          public void executeService1And2() {
                      service1.method1();
                      service1.method2();
                      
                      service2.method3();
                      service2.method4();
                  }


                  
          public void setService1(Service1 service1) {
                      
          this.service1 = service1;
                  }


                  
          public void setService2(Service2 service2) {
                      
          this.service2 = service2;
                  }

              }


              
          private interface Service1 {

                  
          public void method1();

                  
          public void method2();
              }


              
          private interface Service2 {

                  
          public void method3();

                  
          public void method4();
              }


          1. 普通mock

              @Test
              
          public void testMock() {
                  Business business 
          = new Business();
                  Service1 service1 
          = EasyMock.createMock("service1", Service1.class);
                  business.setService1(service1);
                  
                  service1.method2();
                  EasyMock.expectLastCall();
                  service1.method1();
                  EasyMock.expectLastCall();

                  
                  EasyMock.replay(service1);
                  business.executeService1();
                  EasyMock.verify(service1);
              }


              測(cè)試案例可以通過(guò),說(shuō)明EasyMock.createMock()的確是不檢測(cè)方法的調(diào)用順序。

          2. strict mock

              @Test
              
          public void testStrictMock() {
                  Business business 
          = new Business();
                  Service1 service1 
          = EasyMock.createStrictMock("service1", Service1.class);
                  ...
              }


              案例失敗,錯(cuò)誤信息如下
          java.lang.AssertionError:
            Unexpected method call service1.method1():
              service1.method2(): expected: 1, actual: 0
           at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:45)
           at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:73)
           at net.sourcesky.study.easymock.tutorial.$Proxy4.method1(Unknown Source)
           at net.sourcesky.study.easymock.tutorial.OrderTest$Business.executeService1(OrderTest.java:14)
           at net.sourcesky.study.easymock.tutorial.OrderTest.testStrictMock(OrderTest.java:79)
           ......

              說(shuō)明strict mock下,easymock檢測(cè)到了實(shí)際調(diào)用時(shí)的順序和預(yù)期的不同。

          3. nick mock

              @Test
              
          public void testNiceMock() {
                  Business business 
          = new Business();
                  Service1 service1 
          = EasyMock.createNiceMock("service1", Service1.class);
                  ...
              }

              測(cè)試案例可以通過(guò),而且如果是nick mock的話,record階段可以簡(jiǎn)化:

              @Test
              
          public void testNiceMockSimplify() {
                  Business business 
          = new Business();
                  Service1 service1 
          = EasyMock.createNiceMock("service1", Service1.class);
                  business.setService1(service1);
                  
                  EasyMock.replay(service1);
                  business.executeService1();
                  EasyMock.verify(service1);
              }

              這個(gè)簡(jiǎn)化版本的測(cè)試案例也是可以通過(guò)的。

              上述的測(cè)試案例驗(yàn)證了strict mock和nice mock的基本使用,對(duì)于同一個(gè)mock對(duì)象,strict模式下多個(gè)方法之間的調(diào)用順序在record階段和replay階段下是需要保持一致的。但是故事并不是到此結(jié)束,更有意思的內(nèi)容在后面:如果出現(xiàn)多個(gè)mock對(duì)象,那么這些不同mock對(duì)象的方法之間,他們的調(diào)用順序是否檢測(cè)?普通mock和nice mock模式下自然是不會(huì)檢測(cè)順序,但是strict模式下呢?

              我們來(lái)看需要測(cè)試的方法executeService1And2(),這個(gè)方法會(huì)依次調(diào)用service1和service2的方法。使用easymock測(cè)試這個(gè)方法,注意我們?cè)趓ecord階段依然故意將方法的調(diào)用順序設(shè)置為和實(shí)際不同。

          1. 不使用control,直接創(chuàng)建兩個(gè)strict mock對(duì)象

              @Test
              
          public void testWithoutControlInWrongOrder() {
                  Business business 
          = new Business();
                  Service1 service1 
          = EasyMock.createStrictMock("service1", Service1.class);
                  Service2 service2 
          = EasyMock.createStrictMock("service2", Service2.class);
                  business.setService1(service1);
                  business.setService2(service2);
                  
                  service2.method3();
                  EasyMock.expectLastCall();
                  service1.method1();
                  EasyMock.expectLastCall();
                  
                  EasyMock.replay(service1, service2);
                  business.executeService1And2();
                  EasyMock.verify(service1, service2);
              }

              這個(gè)測(cè)試案例,出于意外的,通過(guò)了。easymock并沒(méi)有檢測(cè)service1.method1()和service2.method3()這兩個(gè)方法的調(diào)用順序。


          2. 使用strict control創(chuàng)建兩個(gè)strict mock對(duì)象

              @Test
              
          public void testWithStrictControlInWrongOrder() {
                  Business business 
          = new Business();
                  IMocksControl mocksControl 
          = EasyMock.createStrictControl();
                  ...
              }

              案例失敗,錯(cuò)誤信息為:

          java.lang.AssertionError:
            Unexpected method call service1.method1():
              service2.method3(): expected: 1, actual: 0
           at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:45)
           at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:73)
           at net.sourcesky.study.easymock.tutorial.$Proxy4.method1(Unknown Source)
           at net.sourcesky.study.easymock.tutorial.OrderTest$Business.executeService1And2(OrderTest.java:19)
           at net.sourcesky.study.easymock.tutorial.OrderTest.testWithStrictControlInWrongOrder(OrderTest.java:218)
           ......

              OK,easymock終于檢測(cè)到service1.method1()和service2.method3()這兩個(gè)方法的調(diào)用順序和期望的不一致了。

              解釋一下,EasyMock.createStrictMock()方法實(shí)際上內(nèi)部是生成一個(gè)新的strict control,然后再創(chuàng)建mock對(duì)象。

                  Service1 service1 = EasyMock.createStrictMock("service1", Service1.class);
                  Service2 service2 = EasyMock.createStrictMock("service2", Service2.class);

              這里實(shí)際是創(chuàng)建了兩個(gè)strict control,而easymock是不會(huì)跨control進(jìn)行順序檢測(cè)的。在實(shí)際使用過(guò)程中,我們會(huì)有大量的場(chǎng)景需要檢測(cè)多個(gè)mock之間的調(diào)用順序(按說(shuō)如果沒(méi)有特殊要求,一般的測(cè)試場(chǎng)景默認(rèn)都應(yīng)該如此),這種情況下就必須使用control, 而且必須是同一個(gè)strict control才能滿足要求。

              教程后面的最佳實(shí)踐中有一條就是推薦使用mock control,可以跨mock對(duì)象檢測(cè)方法調(diào)用順序是一個(gè)重要原因。

           

           

          posted on 2010-11-19 11:39 sky ao 閱讀(2627) 評(píng)論(0)  編輯  收藏 所屬分類: software test

          主站蜘蛛池模板: 偃师市| 昌都县| 雷山县| 南靖县| 泰宁县| 扬中市| 苏州市| 增城市| 手游| 清丰县| 涞源县| 西平县| 寿阳县| 普格县| 闻喜县| 古交市| 牡丹江市| 兴文县| 邛崃市| 乃东县| 德庆县| 潼南县| 揭西县| 鹤山市| 望谟县| 佛山市| 桦甸市| 乌兰察布市| 长垣县| 五指山市| 云霄县| 张掖市| 临沂市| 城市| 金溪县| 新竹县| 湖口县| 哈密市| 齐齐哈尔市| 三穗县| 乐山市|