介紹
如果你沒有執行單元測試,你就會同時失去第一時間改善軟件質量和削減開發時間和成本的機會。這種犧牲當然是令人失望的。在此之前,開發人員一直沒有一種可行的方法來執行單元測試,F在,JAVA開發人員能夠使用ParaSoft的Jtest自動化JAVA單元測試,而C/C++開發人員能夠利用ParaSoft最新的C++Test工具自動化C/C++單元測試。
本文闡述了執行單元測試的方法、優點和難點,然后描述了C++Test任何能夠給C/C++開發人員帶來巨大的好處。
什么是單元測試?
我們對單元測試的定義是測試應用中最小的單元,如C/C++中的一個類。C/C++單元測試的目的是執行每個類中的每一個方法或函數,檢測所有存在的功能性問題、錯誤和構造弱點。發現這些典型的問題通常涉及到三種測試方法:黑盒測試、白盒測試和回歸測試。黑盒測試通過確定類的公共界面是否依照定義執行,檢查類的功能性;執行這種類型的測試不需要有關實現細節的知識。白盒測試通過確定類在遇到非預期輸入時執行是否正確,檢查所有的類的方法和函數(包括保護和私有成員)的健壯性;執行這種類型的測試需要對類的實現細節的完整知識;貧w測試檢查是否類的修改會在原來正確的代碼中引入新的錯誤。
什么是單元測試的優點?
單元測試被公認為軟件開發過程中的一個關鍵步驟。單元測試能夠簡化錯誤檢測,在減少開發時間和成本的同時提高軟件質量。
單元測試促進錯誤檢測的第一個方面是使你更接近錯誤。圖1和圖2說明了這一點。
圖1:應用測試
圖1顯示了一個包含許多對象的應用的測試模型。大橢圓表示應用,小橢圓表示對象,箭頭表示用戶輸入,紅星表示潛在的錯誤。
為了發現錯誤,必須修改輸入,對象間的相互作用將迫使某對象引發潛在的錯誤。這一點無疑是有一定難度的。想象一下你站在一張臺球桌前,所有的球圍成一個三角形放置在桌子中間,要求你一桿擊球將中間的球打入指定的袋中。這是一件多么困難的事情!就像要設計一個輸入從而發現應用中的一個錯誤一樣。由于其難度,開發人員只能依賴應用軟件的運行失敗來發現錯誤,但卻仍然沒有測試到許多類。因此只做集成測試是一件非常困難的事情。
單元級測試提供了一種更有效的發現錯誤的方法。如圖2所示。
圖2:單元測試
單獨測試一個類時(與其它對象分離),由于更接近錯誤,找到潛在的錯誤就會變得容易得多。用上述臺球的例子來比喻,就像是臺面上只有壹兩個球時,一桿將一個球擊入指定的袋中。
單元測試促進錯誤檢測的第二個方面是,將你從在問題中艱難跋涉去修正一個簡單錯誤的困境中解救出來。因為錯誤是相互關聯和作用的,在較高的層次上找到和修正一個錯誤,常常會發現另外的問題。當你在較高層次上測試時,原始的錯誤就象是洋蔥的最內層一樣,另外的錯誤就象緊包著內層的其它層:只有把外層都剝掉才能看到最內層。當你測試每一個類時,錯誤還很少有機會建立在其它錯誤之上,并相互作用引起奇怪的行為。因此在單元級上檢測錯誤會容易的多。
最重要的結果是,更容易的錯誤檢測能夠在改善應用質量的同時大量削減開發時間和成本。首先,由于能夠更容易地找到錯誤,就會減少發現它們的時間和資源。其次,由于你一寫完一個類,就能發現和改正其中的錯誤,你就不需要在以后花費時間重新了解和摸索。最后,最重要的理由是:由于類的相互作用和關聯性,在單元級修改一個類只會影響到原始的類,而在較高的層次上修改一個類可能會改變多個程序部件的設計和功能性。越遲發現問題,通常就要修改越多的代碼。當修改的代碼量增加時,兩個其它因素也會隨之增加:
- 修改每一個錯誤所需的時間和費用。
- 在代碼中引入新的錯誤的機會。
- IBM: 根據IBM的一份內部資料指出,確定軟件錯誤的相對成本是:在設計階段,1.5;編碼前,1;編碼中,1.5;測試前,10;測試中,60;交付后,100。[Watts Humphrey]
- TRW: 確定錯誤的相對時間:需求分析階段,1;設計階段,3-6;編碼階段,10;開發測試階段,15-40;接受性測試階段,30-70;應用運行中,40-1000。[Boehm]
- IBM: 確定錯誤的相對時間:設計評審,1;代碼檢查,20;測試,82。[Remus]
- JPL: Bush得出的每個錯誤的平均成本:編碼,US$90-US$120;測試,US$10,000。[Bush]
- Freedman and Weinberg: 使用設計評審和代碼檢查手段的項目在測試時發現錯誤的數量會減少10倍,測試成本降低50%-8%,包括評審和檢查的成本。[Freedman]
基于上述信息,單元測試看上去就象一劑萬能藥。如果是這樣的話,為什么每一個C/C++開發人員不馬上對每一個類進行單元測試?就目前可以使用的技術來說,對C/C++的單元測試是一件困難、煩瑣和耗時的事情,沒有很好的工具來自動化這一過程,使得許多C/C++開發人員望而生畏。
執行單元測試的第一步是是目標類變得可測。這需要兩個工作:
設計一個運行目標類的測試驅動程序。
設計樁函數,它們為被測類所引用的任何外部資源返回值。
建立一個測試驅動,需要建立一個新的類,除了測試原始類以外它不能用于任何其它目的。測試驅動應該具有下列特性:
- 一個指定設置和清除的標準方式。
- 一個選擇個別測試和所有有效測試的方法。
- 一個分析輸出的預期(或非預期)結果的機制。
- 一個標準的錯誤報告形式。
如果你的類引用任何還沒有準備好或不可訪問的外部資源(如外部文件、數據庫和CORBA對象等),你必須建立相應的樁函數,它們的返回值類似于這些實際的外部資源應該返回的值。當建立這些樁函數時,你需要選擇樁函數的返回值,它們將影響程序的執行路徑...
為了測試類的功能性必須執行任何的路徑,
足夠的路徑能夠提供徹底的測試覆蓋性。
下一步是設計和建立合適的測試用例。為了徹底地測試類的結構和功能性,你應該設計兩中類型的測試用例:黑盒和白盒。
黑盒測試用例基于說明和規格文檔。特別地,至少應該為規格文檔的每個入口建立一個測試用例;更好的是這些測試用例能夠測試每個入口的各種邊界條件。還需要為發現的每一個錯誤增加另外的測試用例,以及任何你認為必要的其它測試。
白盒測試用例通過各種不同的輸入充分地執行類的所有方法以發現缺陷。對于手工測試來說這是非常困難的。為了建立有效的白盒測試用例,你必須研究類的內部結構,然后編寫測試用例盡可能完全地覆蓋類的所有方法,以及覆蓋所有可能引起類崩潰的輸入。要達到較高的測試覆蓋性,需要有效的白盒測試用例它們能夠執行相當多數的路徑。例如,一個典型的1萬行的程序,大約有1億條可能的路徑;手工建立能夠執行所有這些路徑的輸入幾乎是不可行的。
在建立這些測試用例以后,你將要執行整個測試用例并分析結果,確定在那里出現了錯誤、崩潰和薄弱環節。你還需測量這些測試的覆蓋性,以確定類被測試的程度以及需要追加的測試用例。
任何時候一個類被修改后,你應該執行回歸測試,保證沒有引入新的錯誤和/或原來的錯誤已經被更正了;貧w測試包括白盒和黑盒測試用例,并且分析結果以確定類的質量是否得到的改善。
C++Test: 一個自動化的單元測試解決方案
ParaSoft認識到了C/C++單元測試內在的的價值和難度,開發了C++Test,一個自動的C/C++單元測試工具,增強了ParaSoft的自動錯誤防止和錯誤檢測產品線。C++Test自動執行所有可能的單元測試過程。特別地,它能夠自動:
- 建立每個被測類的測試驅動程序。
- 建立任何必要的樁函數,并允許你定制這些樁函數的返回值或加入自己的樁函數。
- 單鍵執行白盒測試的所有步驟。
- 生成黑盒測試用例的基礎集合。
- 運行黑盒測試用例。
- 生成黑盒測試的輸出結果。
- 執行回歸測試。
- 跟蹤測試覆蓋性。
C++Test還是高度可定制的;例如,你可以改變測試用例的生成參數,過濾一定的文件、類或方法,在任何層次上(從這個項目到單個方法或測試用例)進行測試。
另外,C++Test很容易與你目前的開發過程合作。C++Test直接安裝在DevStudio環境中,因此你能夠立即測試任何正在開發中的類。只要在Developer Studio的工具欄上按下Test File或Test Project按鈕,那么C++Test就會自動在C++Test圖形用戶界面中打開你的文件,為每個類建立一個測試驅動程序并自動測試每個類。
圖3:C++Test圖形用戶界面
通過自動化單元測試過程,C++Test使得單元測試切實可行,即使對時間非常緊張的項目和開發人員也是如此,并且比手工單元測試具有更好的精確行和正確行。這一切將轉化成更高質量的應用,并且以更短的時間以及更低的開發、支持和維護成本。
文章來源于領測軟件測試網 http://www.kjueaiud.com/