您的位置:軟件測(cè)試 > 開(kāi)源軟件測(cè)試 > 開(kāi)源單元測(cè)試工具 >
使用模仿對(duì)象Mock object進(jìn)行單元測(cè)試
作者:網(wǎng)絡(luò)轉(zhuǎn)載 發(fā)布時(shí)間:[ 2013/3/11 17:02:30 ] 推薦標(biāo)簽:

模仿對(duì)象(Mock object)是為起中介者作用的對(duì)象編寫(xiě)單元測(cè)試的有用方法。測(cè)試對(duì)象調(diào)用模仿域?qū)ο螅ㄋ粩嘌砸哉_的次序用期望的參數(shù)調(diào)用了正確的方法),而不是調(diào)用實(shí)際域?qū)ο。然而,?dāng)測(cè)試對(duì)象必須創(chuàng)建域?qū)ο髸r(shí),我們面臨一個(gè)問(wèn)題。測(cè)試對(duì)象如何知道創(chuàng)建模仿域?qū)ο,而不是?chuàng)建實(shí)際域?qū)ο竽兀吭诒疚闹,軟件顧?wèn) Alexander Day Chaffee 和 William Pietri 將演示一種重構(gòu)技術(shù),該技術(shù)根據(jù)工廠方法設(shè)計(jì)模式來(lái)創(chuàng)建模仿對(duì)象。

單元測(cè)試已作為軟件開(kāi)發(fā)的“佳實(shí)踐”被普遍接受。當(dāng)編寫(xiě)對(duì)象時(shí),還必須提供一個(gè)自動(dòng)化測(cè)試類(lèi),該類(lèi)包含測(cè)試該對(duì)象性能的方法、用各種參數(shù)調(diào)用其各種公用(public)方法并確保返回值是正確的。

當(dāng)您正在處理簡(jiǎn)單數(shù)據(jù)或服務(wù)對(duì)象時(shí),編寫(xiě)單元測(cè)試很簡(jiǎn)單。然而,許多對(duì)象依賴(lài)基礎(chǔ)結(jié)構(gòu)的其它對(duì)象或?qū)。?dāng)開(kāi)始測(cè)試這些對(duì)象時(shí),實(shí)例化這些合作者(collaborator)通常是昂貴的、不切實(shí)際的或效率低的。

例如,要單元測(cè)試一個(gè)使用數(shù)據(jù)庫(kù)的對(duì)象,安裝、配置和發(fā)送本地?cái)?shù)據(jù)庫(kù)副本、運(yùn)行測(cè)試然后再卸裝本地?cái)?shù)據(jù)庫(kù)可能很麻煩。模仿對(duì)象提供了解決這一困難的方法。模仿對(duì)象符合實(shí)際對(duì)象的接口,但只要有足夠的代碼來(lái)“欺騙”測(cè)試對(duì)象并跟蹤其行為。例如,雖然某一特定單元測(cè)試的數(shù)據(jù)庫(kù)連接始終返回相同的硬連接結(jié)果,但可能會(huì)記錄查詢(xún)。只要正在被測(cè)試的類(lèi)的行為如所期望的那樣,它將不會(huì)注意到差異,而單元測(cè)試會(huì)檢查是否發(fā)出了正確的查詢(xún)。

夾在中間的模仿

使用模仿對(duì)象進(jìn)行測(cè)試的常用編碼樣式是:

· 創(chuàng)建模仿對(duì)象的實(shí)例

· 設(shè)置模仿對(duì)象中的狀態(tài)和期望值

· 將模仿對(duì)象作為參數(shù)來(lái)調(diào)用域代碼

· 驗(yàn)證模仿對(duì)象中的一致性

雖然這種模式對(duì)于許多情況都非常有效,但模仿對(duì)象有時(shí)不能被傳遞到正在測(cè)試的對(duì)象。而設(shè)計(jì)該對(duì)象是為了創(chuàng)建、查找或獲得其合作者。

例如,測(cè)試對(duì)象可能需要獲得對(duì)Enterprise JavaBean(EJB)組件或遠(yuǎn)程對(duì)象的引用。或者,測(cè)試對(duì)象會(huì)使用具有副作用的對(duì)象,如刪除文件的File對(duì)象,而在單元測(cè)試中不希望有這些副作用。

根據(jù)常識(shí),我們知道這種情形下可以嘗試重構(gòu)對(duì)象,使之更便于測(cè)試。例如,可以更改方法簽名,以便傳入合作者對(duì)象。

在 Nicholas Lesiecki 的文章“Test flexibly with AspectJ and mock objects”中,他指出重構(gòu)不一定總是合意的,也不一定總是產(chǎn)生更清晰或更容易理解的代碼。在許多情況下,更改方法簽名以使合作者成為參數(shù)將會(huì)在方法的原始調(diào)用者內(nèi)部產(chǎn)生混淆的、未經(jīng)試驗(yàn)的代碼混亂。

問(wèn)題的關(guān)鍵是該對(duì)象“在里面”獲得這些對(duì)象。任何解決方案都必須應(yīng)用于這個(gè)創(chuàng)建代碼的所有出現(xiàn)。為了解決這個(gè)問(wèn)題,Lesiecki 使用了查找方式或創(chuàng)建方式。在這個(gè)解決方案中,執(zhí)行查找的代碼被返回模仿對(duì)象的代碼自動(dòng)替換。

因?yàn)?AspectJ 對(duì)于某些情況不是選項(xiàng),所以我們?cè)诒疚闹刑峁┝艘粋(gè)替代方法。因?yàn)樵诟旧线@是重構(gòu),所以我們將遵循 Martin Fowler 在他創(chuàng)新的書(shū)籍“Refactoring: Improving the Design of Existing Code”(請(qǐng)參閱參考資料)中建立的表達(dá)約定。(我們的代碼基于 JUnit — Java 編程的流行的單元測(cè)試框架,盡管它決不是 JUnit 特定的。)


重構(gòu):抽取和覆蓋工廠方法


重構(gòu)是一種代碼更改,它使原始功能保持不變,但更改代碼設(shè)計(jì),使它變得更清晰、更有效且更易于測(cè)試。本節(jié)將循序漸進(jìn)地描述“抽取”和“覆蓋”工廠方法重構(gòu)。

問(wèn)題:正在測(cè)試的對(duì)象創(chuàng)建了合作者對(duì)象。必須用模仿對(duì)象替換這個(gè)合作者。

重構(gòu)之前的代碼:

class Application {
...
  public void run() {
    View v = new View();
    v.display();
...
 


解決方案:將創(chuàng)建代碼抽取到工廠方法,在測(cè)試子類(lèi)中覆蓋該工廠方法,然后使被覆蓋的方法返回模仿對(duì)象。后,如果可以的話(huà),添加需要原始對(duì)象的工廠方法的單元測(cè)試,以返回正確類(lèi)型的對(duì)象:

重構(gòu)之后的代碼:

class Application {
...
  public void run() {
    View v = createView();
    v.display();
...
  protected View createView() {
    return new View();
  }
...
}
 


該重構(gòu)啟用清單1中所示的單元測(cè)試代碼:

清單 1. 單元測(cè)試代碼

class ApplicationTest extends TestCase {
  MockView mockView = new MockView();
  public void testApplication {
    Application a = new Application() {
      protected View createView() {
        return mockView;
      }
    };
    a.run();
    mockView.validate();
  }
  private class MockView extends View
  {
    boolean isDisplayed = false;
    public void display() {
      isDisplayed = true;
    }
    public void validate() {
      assertTrue(isDisplayed);
    }
  }
}

上一頁(yè)123下一頁(yè)
軟件測(cè)試工具 | 聯(lián)系我們 | 投訴建議 | 誠(chéng)聘英才 | 申請(qǐng)使用列表 | 網(wǎng)站地圖
滬ICP備07036474 2003-2017 版權(quán)所有 上海澤眾軟件科技有限公司 Shanghai ZeZhong Software Co.,Ltd