您的位置:軟件測試 > 開源軟件測試 > 開源單元測試工具 >
使用模仿對象Mock object進行單元測試
作者:網絡轉載 發(fā)布時間:[ 2013/3/11 17:02:30 ] 推薦標簽:

后退到測試類內部,我們將 MockTransaction 類定義為成員類,如清單 5 中所示:

清單 5. 將 MockTransaction 定義為成員類:

private MockTransaction extends Transaction {
    private boolean processCalled = false;
    // override process method so that no real work is done
    public void process() {
      processCalled = true;
      setStatus(Status.SUCCESS);
    }
    public void validate() {
      assertTrue(processCalled);
    }
  }
 


后,我們可以重寫測試,以便被測試的對象使用 MockTransaction 類,而不是使用實際類,如清單 6 中所示:

清單 6. 使用 MockTransaction 類

MockTransaction mockTransaction;
  public void testCheckingWithdrawal() {
    mockTransaction = new MockTransaction();
    AtmGui atm = new AtmGui() {
        protected Transaction createTransaction() {
          return mockTransaction;
        }
    };
    insertCardAndInputPin(atm);
    atm.pressButton("Withdraw");
    atm.pressButton("Checking");
    atm.pressButtons("1", "0", "0", "0", "0");
    assertContains("$100.00", atm.getDisplayContents());
    atm.pressButton("Continue");
    assertEquals(100.00, mockTransaction.getAmount());
    assertEquals(TEST_CHECKING_ACCOUNT,
mockTransaction.getSourceAccount());
    assertEquals(TEST_CASH_ACCOUNT,
mockTransaction.getDestAccount());
    mockTransaction.validate();
}
 


該解決方案產生了一個稍長的測試,但該測試只關注正在測試的類的直接行為,而不是 ATM 接口之外整個系統的行為。也是說,我們不再檢查測試帳戶的終余額是否正確;我們將在對 Transaction 對象的單元測試中檢查該函數,而不是在對 AtmGui 對象的單元測試中。

注:根據模仿對象的創(chuàng)造者所說,它應該在其 validate() 方法內部執(zhí)行自己的所有驗證。在本示例中,為了清晰起見,我們將驗證的某些部分放在了測試方法內部。隨著您更加熟練地使用模仿對象,對于將多少驗證職責代理給模仿對象,您將會深有體會。

內部類魔法

在清單 6 中,我們使用了 AtmGui 的匿名內部子類來覆蓋 createTransaction 方法。因為我們只需要覆蓋一個簡單的方法,所以這是實現我們目標的簡明方法。如果我們覆蓋多個方法或在許多測試之間共享 AtmGui 子類,那么創(chuàng)建一個完整的(非匿名)成員類是值得的。

我們還使用了實例變量來存儲對模仿對象的引用。這是在測試方法和特殊化類之間共享數據的簡單方法。這是可以接受的,因為我們的測試框架不是多線程的或可重入的。(如果它是多線程的或可重入的,則必須用 synchronized 塊保護我們自己。)

后,我們將模仿對象本身定義為測試類的專用內部類 — 這通常是一種便利的方法,因為將模仿對象放在使用它的測試代碼旁邊會更加清楚,又因為內部類有權訪問包含它們的類的實例變量。

小心不出大錯

因為我們覆蓋了工廠方法來編寫這個測試,所以其結果是:我們的測試不再包括任何原始創(chuàng)建代碼(現在它在基類的工廠方法內部)。添加確實包括該代碼的測試也許是有益的。這與調用基類的工廠方法并斷言返回對象具有正確類型一樣簡單。例如:

AtmGui atm = new AtmGui();
    Transaction t = atm.createTransaction();
    assertTrue(!(t instanceof MockTransaction));
 
注:相反,assertTrue(t instanceof Transaction) 不能滿足,因為 MockTransaction 也是 Transaction。


從工廠方法到抽象工廠


此時,您可能很想更進一步并用成熟的抽象工廠對象替換工廠方法,如 Erich Gamma 等人在設計模式中詳細描述的那樣。(請參閱參考資料)。實際上,許多人已經用工廠對象來著手這種方法,而不是用工廠方法 — 我們以前是這樣做的,但很快放棄了。

將第三種對象類型(角色)引入系統會有一些潛在的缺點:

它增加了復雜性,而沒有相應地增加功能。

它會迫使您更改目標對象的公用接口。如果必須傳入抽象工廠對象,那么您必須添加一個新的公用構造函數或賦值(mutator)方法。

許多語言對于“工廠”這一概念都附有一些約定,它們會使您誤入歧途。例如,在 Java 語言中,工廠通常作為靜態(tài)方法實現;在這種情況下,這是不合適的。

請記住,本練習的宗旨是使對象更易于測試。通常,用于可測性的設計可以將對象的 API 推向一種更清晰更模塊化的狀態(tài)。但它會走得太遠。測試驅動的設計更改不應該污染原始對象的公用接口。

在 ATM 示例中,對于產品代碼,AtmGui 對象始終只產生一種類型的 Transaction 對象(實際類型)。測試代碼希望它產生另一種類型的對象(模仿對象)。但強迫公用 API 適應工廠對象或抽象工廠(只因為測試代碼要求它這樣)是錯誤的設計。如果產品代碼無需實例化該合作者的多個類型,那么添加該功能將使終的設計不必要地變得難于理解。

參考資料

由 Tim Mackinnon、Steve Freeman 和 Philip Craig 合著的文章“Endo-Testing: Unit Testing with Mock Objects”介紹了術語模仿對象。

Mock Objects Project 是支持模仿對象實現的框架。

工廠方法和抽象工廠設計模式的來源是由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides(也稱為四人組(Gang of Four))合著的 Design Patterns: Elements of Reusable Object-Oriented Software(Addison-Wesley,1997 年)。

如果您不熟悉設計模式,那么您還需要學習這個由兩部分組成的免費教程:

Java design patterns 101(developerWorks,2002 年 1 月)介紹了模式。

Java design patterns 201(developerWorks,2002 年 4 月)介紹了四人組未描述到的其它模式。

請閱讀在線文章 The Factory Method Design Pattern。

由 Martin Fowler 維護的 Refactoring Home Page 是程序員的主要參考資料。

另外,由 Martin Fowler 編寫的 Refactoring: Improving the Design of Existing Code(Addison-Wesley,1999 年)值得一讀。

JUnit 是流行的 Java 語言的單元測試框架。

請參考 Purple Technology 的 XP 和重構參考資料列表。

由 XP 教練和 Java 開發(fā)人員 Roy Miller 合著的專欄文章 Demystifying Extreme Programming 洞察了這個方法,其中,測試是關鍵組件。請務必訪問一下附隨的論壇。

Nicholas Lesiecki 的“Test Flexibly with AspectJ and mock objects”(developerWorks,2002 年 5 月)詳細地描述了在單元測試時如何使用 AspectJ 和模仿對象。

由 Eric Allen 著的“Diagnosing Java code: Unit tests and automated code analysis working together”(developerWorks,2002 年 10 月)研究了單元測試和靜態(tài)分析之間的關系。

WebSphere 開發(fā)者園地中“Application Quality Assurance: Unit Testing”一文研究了使用 JUnit 的單元測試。

WebSphere 開發(fā)者園地中“Debugging and Unit-Testing Server-Side Web Applications”一文也描述了包括交互式調試和迭代單元測試的服務器端 Web 開發(fā)的方案。

在 developerWorks Java 技術專區(qū)可找到數百篇有關 Java 技術的文章和教程。

關于作者

Alexander Day Chaffee 是 Purple Technology 的創(chuàng)辦人,該公司提供了 Java 語言、極端編程和開放源碼咨詢和培訓。他管理 jGuru 的 Servlets FAQ。作為 EarthWeb 的軟件工程主管,Alex 與人共同創(chuàng)建了 Gamelan,這是 Java 社區(qū)的正式目錄?梢酝ㄟ^ alex@jguru.com 與他聯系。

William Pietri 的父親是一位系統分析師和企業(yè)家,William 在十三歲時開始利用計算機賺取午餐費。從那以后,他幾乎從事過技術領域的各個方面,從技術支持到系統管理到軟件工程到用戶界面設計。他是 Scissor(技術咨詢公司)的創(chuàng)辦人?梢酝ㄟ^ william@scissor.com 與 William 聯系。

上一頁123下一頁
軟件測試工具 | 聯系我們 | 投訴建議 | 誠聘英才 | 申請使用列表 | 網站地圖
滬ICP備07036474 2003-2017 版權所有 上海澤眾軟件科技有限公司 Shanghai ZeZhong Software Co.,Ltd