Calvin's Tech Space

          成于堅忍,毀于浮躁

             :: 首頁 :: 聯系 :: 聚合  :: 管理

          認識Mock Object

          版權聲明:轉載時請以超鏈接形式標明文章原始出處和作者信息及本聲明
          http://bigwhite.blogbus.com/logs/535124.html

           

          上周六我們Dominoo group討論(以下稱討論)TDDJUnit的時候,提到過Mock Object,那次可能是我第一次聽到Mock Object這個概念,程序員對新鮮的的東西都是敏感的,所以今天晚上花了一些時間了解了一下Mock Object的概念,做了一些簡單實踐。

           

          術語

          Tested Object – 被測對象

          Mock – 假的 or 仿制的對象

           

          What is Mock Object?

          在討論中我大致了解到Mock Object一般是用來做輔助單元測試,它負責隔離Tested Object與真實環境中模塊或實體(Real world object)的交互,并“替代”or “冒充這些真實模塊或實體與Tested Object進行交互。

          在“JUnit in action”這本書中關于Mock Object的描述如下:

          A mock object (or mock for short) is an object created to stand in for an object that your code will be collaborating with. Your code can call methods on the mock object, which will deliver results as set up by your tests.

           

          Mock Object給我帶來什么好處?

           

          看看下面的圖:

          |-----------------------------------------------------------------|

          |                                                                                         |                   

          |      |---------------------|                                                  |             |-----------------------------|

          |      |   Tested             | <------------------------------------------à | External Mock Object |

          |      |      Object            |                                                    |            |----------------------------|

          |      |---------------------|                                                 |

          |                   /|\               |--------------------|                       |

          |                    |-------|  Internal Mock    |                       |

          |                                     |     Object           |                       |

          |                                     |--------------------|                    |

          |      [Your system scope]                                                  |

          |--------------------------------------------------------- --------|

           

          在測試你的Tested Object時,你可能會與你系統內的某個模塊或系統外某個實體交互,而這些模塊或實體在你做單元測試的時候可能并不存在,這時:

          Ø         Internal Mock Object可能是一個你的系統尚未完成的模塊的“替身”(replacement)

          Ø         External Mock Object可能是測試你的Tested Object時需要的外部的環境實體的“替身”(replacement)。

          不知道這樣給Mock Object分類是否正確J

           

          我們來看看與Real world object交互有什么不足之處:

          Ø         Real world object的行為具有不確定性,我們難于控制它們的輸出or返回結果。

          Ø         Real world object有些時候是難于被建立的或者說是無法獲得的。

          Ø         Real world object的有些行為難于被觸發,如磁盤已滿,網絡error等。

          Ø         Real world object可能不存在,比如你的Tested Object需要與你的系統的另一個module交互,而另一個module尚未開發完畢。

           

          當然還不止這些,我們僅僅是列出一部分。

           

          使用Mock Object替代Real world object后我們就會解決上述問題,換句話說當上面的情況出現后,我們就可以使用Mock Object。這也是什么時候該使用Mock Objectanswer

          Mock Object是我們自己編寫的,我們擁有控制它的絕對的權力,我們可以定制它的行為和輸出。

           

          Use Mock Object

          使用Mock Object解決上述問題可分三步走:

           

          1. Use an interface to describe the object

          2. Implement the interface for production code

          3. Implement the interface in a mock object for testing [3]

          還有一點就是對于Internal Mock Object早晚你要實現出其Real world object的,因為那是你系統的一部分。

           

          一個改自資料[3]的例子

          public interface Environmental {

          public long getTime();

          // Other methods omitted...

          }

          對于這樣一個接口,我們提供兩種實現,

          //real world object

          public class SystemEnvironment implements Environmental {

          public long getTime() {

          return System.currentTimeMillis();

          }

          // other methods ...

          }

           

          //mock object

          public class MockSystemEnvironment implements Environmental {

          public long getTime() {

          return currentTime;

          }

          public void setTime(Time aTime){

                   this.currentTime = aTime;

          }

          private Time currentTime;

          //others

          }

          我們可以看到在MockSystemEnvironment中我們提供“setTime”函數是為了提供控制Mock Object的接口。

           

          我們要測試的類

          //TestedObject

          public class TestedObject{

                   private Environmental env;

                   TestedObject(Environmental aEnv){

                             this.env = aEnv;

          }

          public boolean isAm(){

                   Calendar cal = Calendar.getInstance();

          cal.setTimeInMillis(env.getTime());

          int hour = cal.get(Calendar.HOUR_OF_DAY);

                   if (hour <=12) return true;

                   return false;

          }

          }

           

          將要測試的類放入單元測試框架

          public class TestTestedObject extends TestCase {

                  public void testIsAm(){

                            MockSystemEnvironment env = new MockSystemEnvironment();

                             // Set up a target test time

          Calendar cal = Calendar.getInstance();

          cal.set(Calendar.YEAR, 2004);

          cal.set(Calendar.MONTH, 10);

          cal.set(Calendar.DAY_OF_MONTH, 1);

          cal.set(Calendar.HOUR_OF_DAY, 16);

          cal.set(Calendar.MINUTE, 55);

          long t1 = cal.getTimeInMillis();

          env.setTime(t1);

           

                             TestedObject to = new TestedObject(env);

                             assertFalse(to.isAm());

          }

          }

          在該單元測試中我們使用了Mock Object,并且在使用前我們利用setTime接口,輸入了我們需要的值。結果我們會通過測試。如果我們使用Real Object,我們得到的測試結果將是不固定的,后者可不是所期望的。從這個例子中你也應該體會到Mock object的一些好處了。

           

          如果我們總是手動寫我們需要的Mock Object,那將是一個很大的工作量。現在業界有了Mock Objectseasy mock等開源框架的支持,是我們編寫Mock object變得越來越容易。

           

          參考資料:

          1、《Test-Driven Development – A practical guide

          2、《JUnit in action

          3、《Pragmatic Unit Testing

          posted on 2009-08-16 16:16 calvin 閱讀(567) 評論(0)  編輯  收藏 所屬分類: 軟件測試

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 根河市| 扎兰屯市| 沾化县| 辉南县| 大厂| 特克斯县| 阿克苏市| 小金县| 城口县| 京山县| 阳谷县| 囊谦县| 娱乐| 南开区| 泽库县| 汪清县| 扶沟县| 勃利县| 来安县| 新龙县| 庆云县| 许昌县| 禹州市| 南木林县| 乌拉特后旗| 前郭尔| 定兴县| 定安县| 南京市| 伊宁县| 富源县| 乌兰浩特市| 张家口市| 达日县| 宿迁市| 龙陵县| 且末县| 抚松县| 苍山县| 遂昌县| 政和县|