[轉載]測試驅動開發之模擬對象(概念篇)

1、前言

在測試驅動開發過程當中咱們最關注的是以下一些內容:
目標專注的測試:理想狀況下每一個測試只有一條斷言;
彼此獨立的測試:對於每一個測試都存在預設環境(Fixture)的創建和清除,以便讓測試可以以任意順序執行;
運行速度的測試:你想可以頻繁地運行這些測試。

以 上目標天然致使一種潛在的矛盾。由於簡短而專注的測試就意味着你將會有許多這樣的測試,從而保證每一個都很是簡短而專注。而要想使這些測試彼此獨立,顯然就 須要針對每一個測試都有整潔的預設環境。此外,上面咱們最後一個目標便是:但願測試速度執行神速......儘量地快......以便咱們至關頻繁地執行 它們(由於咱們如今在作測試編程,而仍是根本目標--最終的目標編程)。
對於中小型目標來講,以上預設環境的創建彷佛不成問題;可是,在開發大型項目時,若是測試的預設環境變得至關複雜並且構造或清除起來很是困難時,咱們該怎麼辦呢?
針 對以上問題,有些開發人員可能想到建立大量的預設環境代碼,而有些開發人員所在的工做環境多是一種大型的、複雜的系統--這種環境多是數據庫、工做流 系統或者是某種你正在爲其開發擴展模塊的系統。爲此,你的預設環境代碼須要使系統進入某種特定的狀態,以便按照測試所須要的方式進行響應,這種工做不大可 能很快就完成。
若是存在以上難以處理的測試資源的話,咱們如何在專注性、獨立性和速度這三個目標之間進行權衡呢?數據庫

實踐證實:模擬對象(即Mocks)是一種極其有效可靠的解決方案。當咱們很難或不可能爲某種難以處理的資源建立須要的狀態或訪問那種資源受到限制時,就能夠充分發揮模擬對象的做用。其實,模擬對象還有其餘重要做用。在本篇中,咱們將詳細探討什麼是模擬對象及其可能發揮的有關做用。編程

2、什麼是模擬對象(Mocks)

根據測試驅動開發權威人士的解釋,模擬對象(即Mocks)用來取代真實對象的位置,用於測試一些與真實對象進行交互可依賴於真實對象的功能。模擬對象(即Mocks)背後的基本思想是建立輕量級的、可控制的對象來代替爲了編寫測試而須要使用的對象。此外,模擬對象(即Mocks)還可以讓你指定和測試你的代碼與模擬對象(即Mocks)自己之間的交互。框架

3、模擬對象的用途總結

除了能夠保持測試預設環境的輕量級,以即可以快速地建立和清除外,使用模擬對象還有其餘一些好處。咱們使用模擬對象的緣由至關之多。具體說來,有如下諸多理由要求咱們採用模擬對象的輔助解決方案:工具

(1)有助於保持設計的鬆耦合性

採用模擬對象有助於咱們強化以接口爲中心的設計。針對模擬對象進行編程能夠消除依賴對象內部實現的可能性。單元測試

(2)檢查你的代碼使用另外一個對象是否得當

經過在模擬對象中設按期望值(Expectation),咱們能夠驗證編寫的代碼是否恰當地使用了模擬的接口。測試

(3)由內而外地利用測試來驅動代碼的開發

經過在模擬對象中設定返回值,能夠爲咱們正在開發的代碼提供特定的信息,而後測試最終的行爲是否正確。網站

(4)可讓測試運行得更快

經過模擬諸如通訊或數據庫這樣的子系統,咱們可以避免設置和清除鏈接等資源所帶來的開銷。this

(5)可讓咱們更容易地開發與硬件設備、遠程系統以及其餘一些難以處理的資源進行交互的代碼

若是咱們所編寫的代碼須要與一些難以處理的資源進行交互的話,那麼咱們能夠建立一個代理層來隔離實際的資源。這樣,咱們就可以使用代理層的模擬對象,無需訪問實際的設備或系統就能夠開發代碼。編碼

(6)推遲必需的類實現

針對那些還沒有編寫出來的可是咱們正在開發的代碼而又須要與之進行交互的類來講,咱們可使用它們的模擬對象。這樣,咱們就可以推遲實現這些類,以便集中精 力處理這些類與咱們正在編寫的代碼之間的接口。從而,咱們能夠針對具體實現做出決定,直到咱們瞭解了更多的信息之後再做決定。若是你的測試所須要的只是模 擬行爲,那麼使用模擬對象就足夠了。spa

(7)可讓咱們在進行測試驅動開發時把要開發的部件與系統的其餘部分分隔開來

經過模擬咱們正在編寫的代碼必需要與之交互的部件,咱們能夠單獨專一於這個部件的開發。這樣以來,咱們的開發速度就會更快,由於咱們正在開發的部件與其餘部件之間的複雜的交互徹底處於咱們的控制之下。

(8)提倡基於接口的設計

注意,當你使用以接口爲主(或指導思想)的編程理念時才易於使用模擬對象。

(9)鼓勵使用組合而不是繼承進行程序設計

在OOP設計思想影響下,大多數人總會過分地使用繼承技術。結果是,基於繼承層次而構建出一種一體化的功能。一個類永遠是它所繼承的那種樣子。因而致使: 模擬位於繼承層次中的類的任何一個方面都變得至關困難,由於這個類還要承載它所繼承的全部的負擔。這種想要對特定方面(例如持久性存儲)實施模擬的願望使 咱們傾向於編寫出相對較小的類,這些類經過與其餘類的相互協做而可以實現豐富的功能。這種類的不一樣實現,包括模擬對象在內,都可以很容易地相互替換。

(10)改進接口

使用你最終須要實現的類的模擬,可讓你早早地有機會思考接口並改進之。這在使用測試優先的設計時尤爲如此。你不得不從將要使用這個接口的類的角度來考慮這個接口--由於你開始編寫的是一個使用這個接口的真實的測試程序。

(11)用來測試非同尋常的、不大可能出現的例外狀況

你能夠建立一個模擬對象,讓它返回在一般狀況下不會返回的返回值,或是建立一個能夠在須要的時候拋出異常的模擬對象。這樣可讓你很容易地對異常處理進行測試。總之,出現測試的目的,你徹底能夠編寫出一個可以模擬任何難以發生的狀況下模擬。

4、經常使用模擬框架簡介

最開始,Mock Object是徹底由測試者本身手工撰寫的。這樣,無可避免的會帶來編寫測試用例效率低下和測試用例編寫困難的弊病,甚至可能會影響XP實踐者「測試先行」的激情。此時,各類各樣幫助建立Mock Object的工具就應運而生了。
目前,在Java陣營中主要的Mock測試工具備JMock,MockCreator,MockRunner,EasyMock,MockMaker等,在微軟的.Net陣營中主要是NMock,.NetMock,Rhino Mocks和Moq等。

(1)MockObjects

咱們可使用四種方式來利用MockObjects編寫測試用例:
    一、基於MockObjects的框架編寫本身的Mock Object實現並與其餘人分享;
    二、直接使用MockObjects提供的Mock Object進行測試;
    三、使用其中包含的DynaMock模塊快速獲取Mock Object實例;
    四、經過它提供的Helpers對象幫助咱們快速構建測試環境。

(2)MockMaker

主頁爲http://mockmaker.sourceforge.net/。目前這個框架彷佛發展緩慢,這從它針對的應用平臺爲Windows 2000, Linux, Java 1.2 & Java 1.4這一點能夠看得出。

(3)MockCreator

JAVA平臺的模擬對話框架,開源網址爲http://mockcreator.sourceforge.net/,最新下載支持爲MockCreator-2006-09-07。

(4)EasyMock 

手動的構造 Mock 對象會給開發人員帶來額外的編碼量,並且這些爲建立 Mock 對象而編寫的代碼頗有可能引入錯誤。目前,有許多開源項目對動態構建 Mock 對象提供了支持,這些項目可以根據現有的接口或類動態生成,這樣不只能避免額外的編碼工做,同時也下降了引入錯誤的可能。

EasyMock 是一套用於經過簡單的方法對於給定的接口生成 Mock 對象的類庫。它提供對接口的模擬,可以經過錄制、回放、檢查三步來完成大致的測試過程,能夠驗證方法的調用種類、次數、順序,能夠令 Mock 對象返回指定的值或拋出指定異常。經過 EasyMock,咱們能夠方便的構造 Mock 對象從而使單元測試順利進行。

(5)NMock 

NMock 是一個基於動態代理的模擬工具,用於 C# 開發。NMock使用了代理模式,這容許類實現一個接口並以代理的方式將其它對象的調用轉向。NMock生成的模擬是經過在運行時使用動態代理來實現的, 這容許模擬對象動態的定義,並不須要添加任何附加的類。一般,一個模擬的實現基於被依賴的接口而建立;NMock支持對接口和類的模擬,另外它還支持屬性 模擬。

(6)Rhino Mocks和Moq

Rhino Mocks和Moq是.NET平臺下的兩個新建立的優秀的模擬對象框架,有關於此兩者的對比,讀者能夠參考中文博客「比較Moq和Rhino Mocks兩個測試框架」,URL爲:http://blog.joycode.com/haacked/archive/2008/03/24/115023.aspx。從許多的博客文章中能夠看到,這兩個框架在.NET平臺下獲得了普遍應用,頗受好評。

(7)JMock

JMock利用模擬對象思想來對Java代碼進行測試。歸納來看,JMock具備如下特色:容易擴展,讓你快速簡單地定義模擬對象,所以沒必要打破程序間的關聯,讓你定義靈活的超越對象之間交互做用而帶來測試侷限,減小你測試地脆弱性。

篇幅所限,在此僅僅列舉上面幾種常見的模擬對象框架,並且僅僅做了簡單介紹。至於各類框架的具體特徵與相應示例展現,請參考各框架的官方網站。

    5、小結

從簡短的文章介紹,能夠看出模擬對象確實可以協助咱們實如今本文開始所關注的三個目標,即:目標專注的測試;彼此獨立的測試和快速的測試。到目前爲止,模擬對象仍然是一種至關年輕的概念,有關的新工具和新技術將不斷被開發出來。針對.NET 2.0框架的Moq就是例證之一。

切記:個別狀況下,可能還須要經過手工方式建立模擬類(這些可能要用到MockObjects這樣的框架)。儘管如此,你仍然可以經過使用像本文所給出的模擬框架這樣的工具來建立模擬類的框架代碼--你能夠基於它們所產生的框架代碼進一步增長定製的行爲。

最後還要牢記:模擬對象是一種測試驅動開發的很是好的技術,由於有些狀況下它實在很是有用,可是不要過分使用或過分依賴於它。它僅僅是軟件開發中錦囊中的妙計之一,具體的應用則真正環境而定。

原文連接:http://space.itpub.net/14518332/viewspace-430102

相關文章
相關標籤/搜索