測試驅動的開發概述
作者: 未知 來源: 網絡轉載
一、簡介(Introduction)
你可能已經聽說了這個新名詞:測試驅動的開發(test-driven development),它在廣大程序員、各種雜志和網絡中程序員常去的地方都非常流行。它究竟是什么呢?測試驅動的開發是一種方法理論,它強調把測試作為開發過程的一個主要部分。要是關心程序質量的話,在部署之前前就應該測試。幾乎所有人都使用某種方法進行測試,所以你可能會問:測試不已經是開發過程的一個部分了嗎?測試驅動的開發要讓測試成為開發過程的主要部分。
二、手工測試(Manual Testing)
早期的軟件開發時,許多人的測試方法就是運行程序,通過手工操作來指定輸入然后觀察輸出?,F在還有很多軟件的開發繼續著這種方式。它有一個關鍵的優點:非常容易學習和理解。如果你有鍵盤和鼠標,并且會操作圖形界面,你就可以測試任何桌面應用。如果你有web瀏覽器,你還可以測試web應用。這根本談不上什么技巧,你可以認為所有開發人員都能做到。手工操作時你看到的應用和最終用戶看到的完全相同,這也是一個不錯的主意,但并不是真正的優點,因為其它的測試方法也能做到。
手工測試的缺點就實在太多了:
手工測試需要反復進行。每一次修改程序,不管是增加新特征,改變已有行為,還是修改bug,你都必須重新測試被影響的部分,才能保證你增刪改的代碼不會造成破壞。
手工測試可能帶來錯誤。人類不適合作重復性的工作,特別是這個工作還很煩人的話。人類經常忽略細節,這會導致代碼被破壞。更可能造成的問題是:修改這個地方,可能會影響到另一些代碼的行為,盡管它們的關系不是很明顯。因此,即使你作了非常認真負責的測試,那也只限于你認為修改可能影響到的部分,你還是有可能會在其它地方漏掉一些bug或被破壞的功能,不是因為你不夠仔細,而是因為軟件開發是綜合性的工作,軟件的各個部分常常有關聯,在現在的軟件項目中,任何人都不可能詳細了解某段代碼所有的依賴和被依賴關系。
手工測試無法對不可視組件進行單獨測試。如果你只測你能看到的,那你就沒測你看不到的。這看上去是非常簡單的一個命題,但它的意義重大。軟件是復雜的,為了定位和解決錯誤或被破壞的代碼,大量形態各異的bug需要通過“剝繭抽絲”式的測試去分析每一個組件的行為。對于服務器端軟件尤為如此。服務器端程序中,幾乎所有的重要代碼都在邏輯層,如基于web的程序。表示層測試只能間接的測試業務邏輯,可能忽略某些細節。你當然希望邏輯層和表示層都能很好的工作,但邏輯層正常工作是整個應用能正常運行的基礎。
如果你的測試是手工進行的,別人就沒法判斷你的程序功能是否正確。其他人(例如其他開發人員或者甚至是最終用戶)只能接受你的承諾:你作了測試,各方面都滿足需求。除了你的書面或口頭聲明保證你對程序作過測試它滿足所有可視的檢查外,其他人沒辦法驗證功能正確,除非他們自己辛苦的作一遍測試,但這個工作可能并不適合他們,因為他們不熟悉程序的邊界條件和邏輯。
三、自動測試(Automated Testing)
自動測試解決了手工測試的不足。因此,要回答“除了軟件開發中一直在做的那些事情外,測試驅動的開發到底意味著什么?”這個問題,測試驅動的開發在整個開發過程中引入自動測試,并不斷改進這些測試以適應程序代碼的擴展。注意這中間的兩個要點,第一,測試是自動的表示它不但可以重復進行,還要很方便移植,可重復是指你可以一遍又一遍的對同樣的代碼進行測試,并且每次都得到同樣的結果;方便移植是指別人可以使用你的測試,自己來驗證你的程序是否能通過這些測試。第二點要求測試的改進包含到程序本身代碼的改進中,測試落后于代碼可不是件好事,因為這樣測試就不能真正的驗證程序功能正確與否,因此測試代碼需要與應用本身的代碼保持同步前進。
軟件的自動測試有兩個主要方法。第一個是通過可重現的recorded macros。Mercury Interactive (http://www.mercuryinteractive.com/products/winrunner/)的WinRunner等就是用的這種方法。盡管很容易建立,但宏是很不穩定的,需要經常修改,因為它們通常依賴于按鈕和組件的物理位置,而不是在parsed document中的結構位置。對開發人員來說,測試框架不管是產生不正確的錯誤信息,還是需要大量的工作才能保持和代碼同步,都是非常痛苦的事情,
第二個進行web應用自動測試的主要方法就是通過編程API。這樣你就有了測試框架,軟件庫可以檢查條件是否滿足,報告錯誤的數量和類型,你可以在測試代碼中調用這個框架。你的測試代碼就是繼承自測試框架的一套標準Java類,它們從應用代碼中初始化對象,調用方法來驗證給定輸入會得到預期的結果。采用編程API方案的包括JUnit、HttpUnit、各種單元測試和黑盒web測試的工具等等。這種方案非常靈活,大多數情況下它大大減少了測試代碼的維護時間,并且使應用中的復雜功能測試成為可能,尤其是服務器端應用。這種測試可交替的調用programmatic testing,API-driven testing,或者programmatic API-driven testing。
相對于recorded macros模式來說,基于API的自動測試方法的第一個弱點是它的需要更長創建時間。當你的問題是鼠標移動和點擊時很難減少設置時間。第二個問題是絕大多數客戶不會寫測試程序的??蛻袅私獾氖菢I務過程,而不是技術,客戶可能覺得移動鼠標和點擊鼠標容易得多,這一點非常重要,如果你想讓客戶在開發過程中就參與進來的話,客戶參與是極限編程的鼓吹者推薦的方法。
雖然如此,基于API的方法在許多方面存在著優越性,可以在大多數應用中使用,因為應用程序隨時間改變的程序非常大,所以花在測試程序維護上的時間比測試程序的創建時間占的比例更大。而且recorded macro方法有一個致命限制:只有在應用代碼寫完之后你才能建立測試。如果你們的開發習慣是不在程序完成前測試,那非常好。否則,如果你堅持測試先行的習慣,正如作者推薦的,那非常不幸recorded macros不適合你,因為在記錄宏進行重放之前,你必須有一個能運行的應用程序。
好的方案可能既有recorded macros測試,又有基于API的程序化測試。通過鼠標拖點式測試你可以讓最終用戶參與到測試中來,保證你的程序滿足業務需求。通過程序化測試則可以在技術角度確保程序組件按預計的情況工作。
使用程序化測試,你有兩種選擇:功能測試和單元測試。功能測試也叫做黑盒測試,是指在不知道(或者忽略)內部實現的情況下,在一個較高的層次上進行測試。功能測試用于驗證程序是否完成業務需求,它模擬采用與最終用戶一致的方式與程序進行交互。最終用戶可能是使用基于web應用的業務人員,也可能是通過你所提供的API來使用你的類庫的開發人員。如果你一定要糾纏概念,功能測試和黑盒測試還是有一些區別的,因為技術上功能測試可以在容器內進行(如果要測得是web程序的話),但實際上絕大多數功能測試是在黑盒中做,除了公布的接口外你一無所知。相反,單元測試包括底層代碼的驗證,為了對確保內部組件沒有問題,必須了解程序的內部結構。你還需要知道那些類和方法的實現。如果要測的程序是給開發人員使用的軟件庫,你的單元測試包括所有重要的類和方法,甚至在發布給用戶的API文檔中沒有列出的內容。功能測試與程序交互的方式是通過點擊按鈕和信息入口,進入程序可見的forms。單元測試與程序的交互是通過Java方法調用來訪問。
對前面提到的手工測試的四個缺陷,自動測試都給出了很好的解決:
原文轉自:http://www.anti-gravitydesign.com