1 基本理論 整理資料時發現以前給兄弟們灌輸的單元測試的一些基本知識,放在這里供大家參考。里面參考了網上 很多朋友的資料,這里沒一一列出,一并謝過。ppt轉的,比較亂,ppt已經上傳到個人資源的,需要的可以去下載看看。不知道怎么搞的,ppt轉成 word格式是正確的,word里粘貼到這里,在編輯方式下也是對的,可是瀏覽文章時就亂七八糟了。只有在記事本里中轉了一下,喪失了很多排版上的信息。 現象 - 投入太多的精力,找 bug,而新的代碼仍然會出現類似 bug;
- 寫完代碼,心里沒底,是否有大量 bug 等待自己;
- 新修改的代碼不知道是否影響其他部分代碼;
- 由于牽扯太多,導致不敢進行修改代碼;
... 一、軟件測試基本理論 - 目的:對軟件測試有個整體認識
- 軟件測試
- 軟件測試分類
- 軟件開發全過程檢測及測試自動化
- V模型與X模型
- TDD( Test-Driven Development)
什么是軟件測試? 在軟件投入運行前,對軟件需求分析、設計規格說明和編碼的最終復審,是軟件質量保證的關鍵步驟。 軟件測試的概念: 軟件測試是為了發現錯誤而執行程序的過程。 或者說,軟件測試是根據軟件開發各個階段的規格說明和程序的內部結構而精心設計一批測試用例(即輸入數據及其預期結果),并利用這些測試用例去執行程序, 以發現程序錯誤的過程。 測試的目的 - 測試是程序的執行過程,目的在于發現錯誤;
- 一個好的測試用例在于能發現至今未發現的錯誤;
- 一個成功的測試是發現了至今未發現的錯誤的測試
- 也可以這樣說,測試的目標是以較少的用例、時間和人力找出軟件中潛在的各種錯誤和缺陷,以確保系統的質量
- 一個被人忽略的軟件測試目的是:測試可以幫助發現當前開發工作所采用的軟件過程(也是一個“軟件”)的缺陷,以便進行改進。
- 首先,測試并不僅僅是為了要找出錯誤。分析錯誤產生的原因和錯誤在開發的哪一個階段產生,具有非常重要的意義。
- 通過分析錯誤產生于哪一個開發階段、而又在哪一個階段被發現,我們可以判斷從錯誤的產生到 錯誤的發現,跨越了多少個開發階段。
- 軟件開發的一條重要原則是盡早發現與修正錯誤。
- 正確分析與利用測試的結果,我們可以非常有效地進行軟件過程改進
軟件測試原則 2-1 - 完全測試程序是不可能的
-輸入量太大 -輸出結果太多 -軟件實現途徑太多 -軟件說明書沒有客觀標準。從不同角度看,軟件缺陷的標準不同。 軟件測試原則 2-2 - 軟件測試是有風險的行為
- 測試無法顯示潛伏的軟件缺陷
- 找到的軟件缺陷越多,就說明軟件缺陷越多
- 并非所有軟件缺陷都能修復
- 軟件測試一項講究條理的技術專業
軟件測試分類 從是否需要執行被測軟件的角度,可分為: -靜態測試 -動態測試 從測試是否針對系統的內部結構和具體實現算法的角度來看,可分為 : -白盒測試 -黑盒測試 軟件測試方法-靜態和動態 - 靜態檢查
確保系統按照組織的標準和過程運行,主要依賴于評審和非運行的手段來檢查。通常包括需求評審、設計評審、代碼走查和代碼檢查。 - 動態檢查
在生命周期中進行測試(運行)。通常包括單元測試、集成測試、系統測試、用戶的驗收測試。 靜態測試 - 審查 (Inspection)
-軟件的一種基本測試方法,它以一系列典型問題為依據進行檢測。 - 走查 (Walkthrough)
-一對一的審查,比審查更加仔細。 - 回顧(Review)
-以發現軟件中存在的錯誤和缺陷為目的的一種軟件測試方法,它是在軟件證實執行之前完成。 靜態和動態測試進行結構和功能測試 測試技術 黑盒測試 黑盒測試也稱功能測試或數據驅動測試,它是在已知產品所應具有的功能,通過測試來檢測每個功能是 否都能正常使用,在測試時,把程序看作一個不能打開的黑盆子,在完全不考慮程序內部結構和內部特性的情況下,測試者在程序接口進行測試,它只檢查程序功能 是否按照需求規格說明書的規定正常使用,程序是否能適當地接收輸入數鋸而產生正確的輸出信息,并且保持外部信息(如數據庫或文件)的完整性。 “黑盒”測試著眼于程序外部結構、不考慮內部邏輯結構、針對軟件界面和軟件功能進行測試。“黑盒”法是窮舉輸入測試,只有把所有可能的輸入都作為測試情況 使用,才能以這種方法查出程序中所有的錯誤。實際上測試情況有無窮多個,人們不僅要測試所有合法的輸入,而且還要對那些不合法但是可能的輸入進行測試。 它不僅應用于開發階段的測試,更重要的是在產品測試階段及維護階段必不可少。主要用于軟件確認測試。 黑盒測試方法主要有: 白盒測試 白盒測試也稱結構測試或邏輯驅動測試,它是知道產品內部工作過程,可通過測試來檢測產品內部動作是否按照規格說明書的規定正常進行,按照程序內部的結構測 試程序,檢驗程序中的每條通路是否都有能按預定要求正確工作,而不顧它的功能。 使用被測單元內部如何工作的信息,允許測試人員對程序內部邏輯結構及有關信息來設計和選擇測試用例,對程序的邏輯路徑進行測試。基于一個應用代碼的內部邏 輯知識,測試是基于覆蓋全部代碼、分支、路徑、條件。 白盒測試的主要方法 主要用于軟件驗證。 使用程序設計的控制結構導出測試用例。 邏輯驅動測試: 主要是測試覆蓋率,以程序內在邏輯結構為基礎的測試。包括以下6種類型: - 語句覆蓋
- 判斷覆蓋
- 條件覆蓋
- 判定-條件覆蓋
- 條件組合覆蓋
- 路徑測試
白盒測試的主要目的 - 保證一個模塊中的所有獨立路徑至少被執行一次;
- 對所有的邏輯值均需要測試真、假兩個分支;
- 在上下邊界及可操作范圍內運行所有循環;
- 檢查內部數據結構以確保其有效性。
概念 - 語句覆蓋:語句覆蓋就是設計若干個測試用例,運行被測試程序,使得每一條可執行語句至少執行一次;
- 判定覆蓋(也稱為分支覆蓋):設計若干個測試用例,運行所測程序,使程序中每個判斷的取真分支和取假分支至少執行一次;
- 條件覆蓋:設計足夠多的測試用例,運行所測程序,使程序中每個判斷的每個條件的每個可能取值至少執行一次;
- 判定-條件覆蓋:設計足夠多的測試用例,運行所測程序,使程序中每個判斷的每個條件的所有可能取值至少執行一次,并且每個可能的判斷結果也至少執行一次, 換句話說,即是要求各個判斷的所有可能的條件取值組合至少執行一次;
- 條件組合測試:設計足夠多的測試用例,運行所測程序,使程序中每個判斷的所有可能的條件取值組合至少執行一次;
- 路徑測試:設計足夠多的測試用例,運行所測程序,要覆蓋程序中所有可能的路徑。
軟件開發全過程檢測及測試自動化 - 單元測試(unit test )
由編程的開發人員自行計劃與完成的,針對單個或相關聯的一組程序單元的測試。 - 組裝測試(inegration test )
計劃于設計階段,由開發人員與測試人員合作完成的,針對結合起來的不同單元以及它們的接口的測試。 - 系統測試(system test ):(可認為包括“可用性與圖形用戶界面測試”)
測試整個系統,以證實它滿足要求所規定的功能、質量和性能等方面的特性。 - 回歸測試(regression test ):
用于驗證改變了的系統或其組件仍然保持應有的特性。 - 驗收測試(acceptance test ):
測試整個系統,以保證其達到可以交付使用的狀態。 V模型 V模型 - 單元測試、集成測試、系統測試、驗收測試。是“從小到大”、“由內至外”、“循序漸進”的測試過程,體現了“分而治之”的思想。
- 單元測試的粒度最小,一般由開發小組采用白盒方式來測試,主要測試單元是否符合“設計”。
- 集成測試界于單元測試和系統測試之間,起到“橋梁作用”,一般由開發小組采用白盒加黑盒的 方式來測試,既要驗證“設計”又要驗證“需求”。
V模型 - 系統測試的粒度最大,一般由獨立測試小組采用黑盒方式來測試,主要測試系統是否符合“需求規格說明書”。
- 驗收測試與系統測試非常相似,主要區別是測試人員不同,驗收測試由用戶執行。
測試內容 - 測試內容一般包含
- 接口與路徑測試。
- 功能測試、健壯性測試、性能測試、用戶界面測試、安全性測試、壓力測試、可靠性測試、安裝 /反安裝測試…
測試階段對應表 接口與路徑測試 3-1 - 接口測試:數據一般通過接口輸入和輸出,接口測試一般是白盒測試的第一步。
― 輸入參數有“典型值”、“邊界值”、“異常值” ― 輸出包括函數的返回值和輸出參數。 ― 實際輸出與期望的輸出不一致,那么說明程序有錯誤。 - 一個函數體內的語句可能只有十幾條,但邏輯路徑可能有成千上萬條。所以應該根據經驗選擇關 鍵的路徑測試。
接口與路徑測試 3-2 - 路徑測試的檢查表
- -數據類型、變量值、邏輯判斷、循環、內存管理、文件I/O、錯誤處理
- 預防一些重要的路徑沒有被測試的措施有:
― 觀察是否有程序語句從來沒有被執行過。 ― 要特別留意函數體內的錯誤處理程序塊。 接口與路徑測試 3-3 功能測試 3-1 - 功能測試的基本方法是構造一些合理輸入(在需求范圍之內),檢查輸出是否與期望的相同。如果兩者不一致,即表明功能有誤。
- 難點在于如何構造有效的輸入。
功能測試 3-2 - 功能測試的測試方法:等價劃分法和邊界值分析法。
― 等價劃分是指把輸入空間劃分為幾個“等價區間”,在每個“等價區間”中只需要測試一個典型值就可以了。等價劃分法來源于人們的直覺與經驗,可令測試事半功 倍。 ― “缺陷遺漏在角落里,聚集在邊界上”。邊界值測試法是對等價劃分法的補充。如果A和B是輸入空間的邊界值,那么除了典型值外還要用A和B作為測試用例。 功能測試 3-3 性能測試 3-1 - 性能測試即測試軟件處理事務的速度,一是為了檢驗性能是否符合需求,二是為了得到某些性能數據供人們參考。
- 絕對值考慮:如數據送輸速率是每秒多少比特。 “相對值”考慮:如某個軟件比另一個軟件快多少倍。
- 性能測試中考慮運行環境的影響:例如網絡環境、計算機主頻,總線結構和外部設備都可能影響軟件的運行速度。
性能測試 3-2 - 性能測試的一些注意事項:
― 應當編寫一段程序用于計算時間以及相關數據。 ― 應當測試軟件在標準配置和最低配置下的性能。 ― 應當關閉那些消耗內存、占用CPU的其它應用軟件(如殺毒軟件)。 ― 應當分檔記錄。例如傳輸文件的容量從100K到1M可以分成若干等級。 ― 同一種輸入情況在不同的時間可能得到不同的性能數據,可以取其平均值。 性能測試 3-3 壓力測試 2-1 - 壓力測試也叫負荷測試,即獲取系統能正常運行的極限狀態。
- 壓力測試的主要任務是:構造正確的輸入,使勁折騰系統卻讓它剛好不癱瘓。
- 壓力測試的一個變種是敏感測試。在某種情況下,微小的輸入變動會導致系統的表現(如性能) 發生急劇的變化。
壓力測試 2-2 其他測試內容 - 健壯性測試
- 用戶界面測試
- 信息安全測試
- 可靠性測試
- 安裝和反安裝測試
測試常見問題 2-1 - 問題1:有了“黑盒”測試為什么還要“白盒”測試?
- 問題2:由于單元測試要寫測試驅動程序,非常麻煩,能否等到整個系統全部開發完后,再集中精力進行一次性地單元測試呢?
- 問題3:如果每個單元都通過了測試,把它們集成一起難道會有什么不妥嗎?集成測試是否多此 一舉?
測試常見問題 2-2 - 問題4:在集成測試的時候,已經對一些子系統進行了功能測試、性能測試等等,那么在系統測試時能否跳過相同內容的測試?
- 問題5:既然系統測試與驗收測試的內容幾乎是相同的,為什么還要驗收測試?
- 問題6:能否將系統測試和驗收測試“合二為一”?
總結 2-1 - 測試可以將測試描述為一個運行程序以發現錯誤的過程。
- 軟件測試的準則:不完全測試、風險測試、無法顯示潛伏錯誤、發現錯誤成線性增長、缺陷不能完全修復、測試有條理規程
- 測試的方法:黑盒/白盒、靜態/動態
- 軟件測試的各個階段:單元測試、集成測試、系統測試、驗收測試
總結 2-2 - 測試的內容包括:接口/路徑測試、功能測試、性能測試、壓力測試、可靠性測試、安全性測試、用戶界面測試、安裝/反安裝測試
X模型 測試驅動開發 - TDD, Test-Driven Development
- 測試驅動開發以測試作為開發過程的中心,它要求在編寫任何代碼之前,首先編寫用于定義產品 代碼行為的測試,而編寫的產品代碼又以使測試通過為目標。測試驅動開發要求測試可以完全自動地運行,在代碼進行重構前必須運行測試。
TDD基本做法 - 1. 寫一個測試程序。
- 2. 讓程序編譯通過。
- 3. 運行測試程序,發現不能運行。
- 4. 讓測試程序可以運行。
- 5. 消除重復設計,優化設計結構。
測試產品說明書 - 對于產品說明書的制定是個很重要的設計階段,產品說明書的質量會直接影響到整個產品開發。
- 測試產品說明書屬于靜態黑盒子測試。
常用測試用語-測試用例 - 測試用例:編寫用于輸入輸入的實際數制和預期結果。測試用例還明確指出使用具體測試用例產生的測試程序的任何限制 。
- 使用目的:
― 測試用例應該設計為能夠快速容易地發現盡可能多的錯誤。 ― 應該通過使用和產生正確和錯誤的輸入和輸出來“檢驗”程序。 ― 其目標是要使用合理范圍內的條件,盡可能全面地測試所有模塊乃至整個系統。 測試與調試-什么是缺陷 - 缺陷:最終產品同用戶的期望不一致
- 缺陷的分類
- 錯誤
- 遺漏
- 超出需求的部分
- 缺陷(未觸發)VS.錯誤(應首先解決)
測試與調試-調試的準則 - 調試的方法:歸納法、演繹法和回溯法。
- 常用調試技術使用診斷輸出語句 (diagnostic output statement)、快照轉儲 (snapshot dump) 以及跟蹤指令的斷點 (instruction-dependent breakpoint)。
二、單元測試基本理論 - 什么是單元測試(Unit Test)
- 什么時候測試?
- 為什么要進行單元測試
- C/C++單元測試問答(摘要)
單元測試(Unit Test) - 工廠在組裝一臺電視機之前,會對每個元件都進行測試,這,就是單元測試。
- 臨時單元測試:代碼覆蓋率要超過70%都很困難
- 充分的單元測試:提高軟件質量,降低開發成本的必由之路。
- 單元測試是在軟件開發過程中要進行的最低級別的測試活動,在單元測試活動中,軟件的獨立單元將在與程序的其他部分相隔離的情況下進行測試。
單元測試(Unit Test) - 對于程序員來說,如果養成了對自己寫的代碼進行單元測試的習慣,不但可以寫出高質量的代碼,而且還能提高編程水平。
- 在一種傳統的結構化編程語言中,比如C,要進行測試的單元一般是函數或子過程。在象C++這樣的面向對象的語言中,要進行測試的基本單元是類。對Ada語 言來說,開發人員可以選擇是在獨立的過程和函數,還是在Ada包的級別上進行單元測試。單元測試的原則同樣被擴展到第四代語言(4GL)的開發中,在這里 基本單元被典型地劃分為一個菜單或顯示界面。
單元測試(Unit Test) - 單元測試不僅僅是作為無錯編碼一種輔助手段在一次性的開發過程中使用,單元測試必須是可重復的,無論是在軟件修改,或是移植到新的運行環境的過程中。因 此,所有的測試都必須在整個軟件系統的生命周期中進行維護。
三、為什么要 進行單元測試 - 一些流行的誤解--反調論證
- 其他好處
- 單元測試的重要性
反證1:單元測試浪費了太多的時間 一旦編碼完成,開發人員總是會迫切希望進行軟件的集成工作,這樣他們就能夠看到實際的系統開始啟動工作了。 這在外表上看來是一項明顯的進步,而象單元測試這樣的活動也許會被看作是通往這個階段點的道路上的障礙, 推遲了對整個系統進行聯調這種真正有意思的工作啟動的時間。 反證1:單元測試浪費了太多的時間 在這種開發步驟中,真實意義上的進步被外表上的進步取代了。系統能夠正常工作的可能性是很小的,更多的情況是充滿了各式各樣的Bug。在實踐中,這樣一 種開發步驟常常會導致這樣的結果:軟件甚至無法運行。更進一步的結果是大量的時間將被花費在跟蹤那些包含在獨立單元里的簡單的Bug上面,在個別情況下, 這些Bug也許是瑣碎和微不足道的,但是總的來說,他們會導致在軟件集成為一個系統時增加額外的工期, 而且當這個系統投入使用時也無法確保它能夠可靠運行。 反證1:單元測試浪費了太多的時間 - 在實踐工作中,進行了完整計劃的單元測試和編寫實際的代碼所花費的精力大致上是相同的。一旦完成了這些單元測試工作,很多Bug將被糾正,在確信他們手頭 擁有穩定可靠的部件的情況下,開發人員能夠進行更高效的系統集成工作。這才是真實意義上的進步,所以說完整計劃下的單元測試是對時間的更高效的利用。而調 試人員的不受控和散漫的工作方式只會花費更多的時間而取得很少的好處。
- 使用AdaTEST和Cantata這樣的支持工具可以使單元測試更加簡單和有效。但這不是必須的,單元測試即使是在沒有工具支持的情況下也是一項非常有 意義的活動。
反證2:僅僅證明代碼做了什么 這是那些沒有首先為每個單元編寫一個詳細的規格說明而直接跳到編碼階段的開發人員提出的一條普遍的抱怨, 當編碼完成以后并且面臨代碼測試任務的時候,他們就閱讀這些代碼并找出它實際上做了什么,把他們的測試工作基于已經寫好的代碼的基礎上。當然,他們無法證 明任何事情。所有的這些測試工作能夠表明的事情就是編譯器工作正常。是的,他們也許能夠抓住(希望能夠)罕見的編譯器Bug,但是他們能夠做的僅僅是這 些。 反證2:僅僅證明代碼做了什么 如果他們首先寫好一個詳細的規格說明,測試能夠以規格說明為基礎。代碼就能夠針對它的規格說明,而不是針對自身進行測試。這樣的測試仍然能夠抓住編譯器的 Bug,同時也能找到更多的編碼錯誤,甚至是一些規格說明中的錯誤。 反證2:僅僅證明代碼做了什么 在實踐中會出現這樣的情況: 一個開發人員要面對測試一個單元時只給出單元的代碼而沒有規格說明這樣吃力不討好的任務。你怎樣做才會有更多的收獲,而不僅僅是發現編譯器的Bug?第一 步是理解這個單元原本要做什么, --- 不是它實際上做了什么。 比較有效的方法是倒推出一個概要的規格說明。這個過程的主要輸入條件是要閱讀那些程序代碼和注釋, 主要針對這個單元, 及調用它和被它調用的相關代碼。畫出流程圖是非常有幫助的,你可以用手工或使用某種工具。 可以組織對這個概要規格說明的走讀(Review),以確保對這個單元的說明沒有基本的錯誤, 有了這種最小程度的代碼深層說明,就可以用它來設計單元測試了。 反證3:我是個很棒的程序員, 我是不是可以不進行單元測試? - 在每個開發組織中都至少有一個這樣的開發人員,他非常擅長于編程,他們開發的軟件總是在第一時間就可以正常運行,因此不需要進行測試。你是否經常聽到這樣 的借口?
- 在真實世界里,每個人都會犯錯誤。即使某個開發人員可以抱著這種態度在很少的一些簡單的程序中應付過去。 但真正的軟件系統是非常復雜的。真正的軟件系統不可以寄希望于沒有進行廣泛的測試和Bug修改過程就可以正常工作。
- 編碼不是一個可以一次性通過的過程。在真實世界中,軟件產品必須進行維護以對操作需求的改變作出反應, 并且要對最初的開發工作遺留下來的Bug進行修改。你希望依靠那些原始作者進行修改嗎? 這些制造出這些未經測試的原始代碼的資深專家們還會繼續在其他地方制造這樣的代碼。在開發人員做出修改后進行可重復的單元測試可以避免產生那些令人不快的 負作用。
反證4:不管怎樣, 集成測試將會抓住所有的Bug ? - 我們已經在前面的討論中從一個側面對這個問題進行了部分的闡述。這個論點不成立的原因在于規模越大的代碼集成意味著復雜性就越高。如果軟件的單元沒有事先 進行測試,開發人員很可能會花費大量的時間僅僅是為了使軟件能夠運行,而任何實際的測試方案都無法執行。
- 一旦軟件可以運行了,開發人員又要面對這樣的問題: 在考慮軟件全局復雜性的前提下對每個單元進行全面的測試。 這是一件非常困難的事情,甚至在創造一種單元調用的測試條件的時候,要全面的考慮單元的被調用時的各種入口參數。在軟件集成階段,對單元功能全面測試的復 雜程度遠遠的超過獨立進行的單元測試過程。
- 最后的結果是測試將無法達到它所應該有的全面性。一些缺陷將被遺漏,并且很多Bug將被忽略過去。
- 讓我們類比一下,假設我們要清洗一臺已經完全裝配好的食物加工機器!無論你噴了多少水和清潔劑,一些食物的小碎片還是會粘在機器的死角位置,只有任其腐爛 并等待以后再想辦法。但我們換個角度想想,如果這臺機器是拆開的, 這些死角也許就不存在或者更容易接觸到了,并且每一部分都可以毫不費力的進行清洗。
反證5:它的成本效率不高 - 一個特定的開發組織或軟件應用系統的測試水平取決于對那些未發現的Bug的潛在后果的重視程度。這種后果的嚴重程度可以從一個Bug引起的小小的不便到發 生多次的死機的情況。這種后果可能常常會被軟件的開發人員所忽視(但是用戶可不會這樣),這種情況會長期的損害這些向用戶提交帶有Bug的軟件的開發組織 的信譽,并且會導致對未來的市場產生負面的影響。相反地,一個可靠的軟件系統的良好的聲譽將有助于一個開發組織獲取未來的市場。
- 很多研究成果表明,無論什么時候作出修改都要進行完整的回歸測試,在生命周期中盡早地對軟 件產品進行測試將使效率和質量得到最好的保證。Bug發現的越晚,修改它所需的費用就越高,因此從經濟角度來看, 應該盡可能早的查找和修改Bug。在修改費用變的過高之前,單元測試是一個在早期抓住Bug的機會。
- 相比后階段的測試,單元測試的創建更簡單,維護更容易,并且可以更方便的進行重復。從全程的費用來考慮, 相比起那些復雜且曠日持久的集成測試,或是不穩定的軟件系統來說,單元測試所需的費用是很低的。
反證5:它的成本效率不高 - 摘自<<實用軟件度量>>(Capers Jones,McGraw-Hill 1991),它列出了準備測試,執行測試,和修改缺陷所花費的時間(以一個功能點為基準),這些數據顯示單元測試的成本效率大約是集成測試的兩倍 系統測試的三倍。
反證5:它的成本效率不高 - (術語域測試(Field test)意思是在軟件投入使用以后,針對某個領域所作的所有測試活動)
- 這個圖表并不表示開發人員不應該進行后階段的測試活動,這次測試活動仍然是必須的。它的真正意思是盡可能早的排除盡可能多的Bug可以減少后階段測試的費 用。
- 其他的一些圖表顯示高達50%的維護工作量被花在那些總是會有的Bug的修改上面。如果這些Bug在開發階段被排除掉的話,這些工作量就可以節省下來。當 考慮到軟件維護費用可能會比最初的開發費用高出數倍的時候,這種潛在的對50%軟件維護費用的節省將對整個軟件生命周期費用產生重大的影響。
反證 結論 - 經驗表明一個盡責的單元測試方法將會在軟件開發的某個階段發現很多的Bug,并且修改它們的成本也很低。在軟件開發的后期階段,Bug的發現并修改將會變 得更加困難,并要消耗大量的時間和開發費用。無論什么時候作出修改都要進行完整的回歸測試,在生命周期中盡早地對軟件產品進行測試將使效率和質量得到最好 的保證。 在提供了經過測試的單元的情況下,系統集成過程將會大大地簡化。開發人員可以將精力集中在單元之間的交互作用和全局的功能實現上,而不是陷入充滿很多 Bug的單元之中不能自拔。
- 使測試工作的效力發揮到最大化的關鍵在于選擇正確的測試策略,這其中包含了完全的單元測試的概念,以及對測試過程的良好的管理,還有適當地使用象 AdaTEST和Cantata這樣的工具來支持測試過程。這些活動可以產生這樣的結果:在花費更低的開發費用的情況下得到更穩定的軟件。更進一步的好處 是簡化了維護過程并降低了生命周期的費用。有效的單元測試是推行全局質量文化的一部分,而這種質量文化將會為軟件開發者帶來無限的商機。
其他好處 1:減少程序的Bug - 要減少軟件中的錯誤數目,方法之一就是擁有一個專業的測試組,其工作就是盡一切可能使軟件 崩潰。不幸的是,如果擁有測試組,那么即使是經驗豐富的開發人員,也會傾向于花費較少的時間來保證代碼的可靠性。
- 軟件界有一句俗語:“開發人員不應該測試他們自己的代碼”。這是因為開發人員對自己的代碼 了如指掌,他們很清楚如何采用適當的方法對代碼進行測試。盡管這句俗語很有道理,但卻忽略了非常重要的一點 - 如果開發人員不對自己的代碼進行測試,又如何知道代碼能否按照預期的方式運行?
- 簡單說來,他們根本無從得知。開發人員編寫那種運行不正常或只在某些情況下運行正常的代碼 是一個嚴重的問題。他們通常只測試代碼能否在很少的情況下正常運行,而不是驗證代碼能夠在所有情況下均正常運行。
其他好處 2:提高開發速度 - 在實踐工作中,進行了完整計劃的單元測試和編寫實際的代碼所花費的精力大致上是相同的。一旦完成了這些單元測試工作,很多Bug將被糾正,在確信他們手頭 擁有穩定可靠的部件的情況下,開發人員能夠進行更高效的系統集成工作。這才是真實意義上的進步,所以說完整計劃下的單元測試是對時間的更高效的利用。而調 試人員的不受控和散漫的工作方式只會花費更多的時間而取得很少的好處。
- 經驗表明一個盡責的單元測試方法將會在軟件開發的某個階段發現很多的Bug,并且修改它們的成本也很低。在軟件開發的后期階段,Bug的發現并修改將會變 得更加困難,并要消耗大量的時間和開發費用。無論什么時候作出修改都要進行完整的回歸測試,在生命周期中盡早地對軟件產品進行測試將使效率和質量得到最好 的保證。 在提供了經過測試的單元的情況下,系統集成過程將會大大地簡化。開發人員可以將精力集中在單元之間的交互作用和全局的功能實現上,而不是陷入充滿很多 Bug的單元之中不能自拔。
其他好處 3:使程序代碼更整潔,優化程序的設計 - 只有自動的單元測試程序失敗時,我們才會去重寫代碼,在測試驅動開發中,要求我們對程序不停的重構,通過重構,我們可以優化程序的結構設計,消除程序中潛 在的錯誤。同時,為了能夠使自己的程序可以很方便的進行測試,開發人員就需要很好地考慮程序的設計,極限編程的方法說可以不需要設計就開始編碼,但實際 上,它在編寫代碼的過程中每時每刻都為了方便的進行和通過測試而在優化自己的設計。它實際上是把開始階段很大很抽象的設計分散到你編寫的每個方法中。因此 他們會說好設計最后會自然而然的出現。
其他好處 4:編寫單元測試代碼的過程實際上就是設計程序的過程 - 在編寫單元測試代碼時,我們實際上是在思考我們的程序根據預期會返回什么結果,它實際上就 是程序設計的過程。而通過重構過程,我們可以對這些設計進行很好的優化。
單元測試的重要性 - 單元測試是軟件測試的基礎,因此單元測試的效果會直接影響到軟件的后期測試,最終在很大程度上影響到產品的質量。
- 時間方面
- 測試效果
- 測試成本
- 產品質量
重要性 1:時間方面 - 如果認真的做好了單元測試,在系統集成聯調時非常順利,因此會節約很多時間,反之那些由于因為時間原因不做單元測試或隨便做做的則在集成時總會遇到那些本 應該在單元測試就能發現的問題,而這種問題在集成時遇到往往很難讓開發人員預料到,最后在苦苦尋覓中才發現這是個很低級的錯誤而在悔恨自己時已經浪費了很 多時間,這種時間上的浪費一點都不值得,正所謂得不償失。
重要性 2:測試效果 - 根據以往的測試經驗來看,單元測試的效果是非常明顯的,首先它是測試階段的基礎,做好了單元測試,在做后期的集成測試和系統測試時就很順利。其次在單元測 試過程中能發現一些很深層次的問題,同時還會發現一些很容易發現而在集成測試和系統測試很難發現的問題。再次單元測試關注的范圍也特殊,它不僅僅是證明這 些代碼做了什么,最重要的是代碼是如何做的,是否做了它該做的事情而沒有做不該做的事情。
重要性 3:測試成本 - 在單元測試時某些問題就很容易發現,如果在后期的測試中發現問題所花的成本將成倍數上升。比如在單元測試時發現1個問題需要1個小時,則在集成測試時發現 該問題需要2個小時,在系統測試時發現則需要3個小時,同理還有定位問題和解決問題的費用也是成倍數上升的,這就是我們要盡可能早的排除盡可能多的bug 來減少后期成本的因素之一。
重要性 4:產品質量 - 單元測試的好與壞直接影響到產品的質量,可能就是由于代碼中的某一個小錯誤就導致了整個產品的質量降低一個指標,或者導致更嚴重的后果,如果我們做好了單 元測試這種情況是可以完全避免的。
- 綜上所述,單元測試是構筑產品質量的基石,我們不要因為節約單元測試的時間不做單元測試或隨便做而讓我們在后期浪費太多的不值得的時間,我們也不愿意因為 由于節約那些時間導致開發出來的整個產品失敗或重來!
四、 C/C++單元測試問答 - 為什么要進行單元測試?
- 由誰進行測試?開發部門還是測試部門?
- 由測試部門進行單元測試為什么成本昂貴?
- 由開發部門進行單元測試能保證測試效果嗎?
- 邊編碼邊測試會影響編碼進度嗎?
- 實施單元測試需要改變開發流程嗎?
- 單元測試測試哪些代碼?
- 實際工作中,單元測試能實現什么程度的測試覆蓋?
- 單元測試如何改良項目代碼的整體結構?
- 我希望依賴全自動的工具來完成單元測試,這一想法現實嗎?
- 如果由開發部門實施單元測試,那么測試部門要做哪些工作?
為什么要進行單元測試? - 單元測試保證局部代碼的質量
- 單元測試改良項目代碼的整體結構
- 單元測試降低測試、維護升級的成本
- 單元測試使開發過程適應頻繁變化的需求
- 單元測試有助于提升程序員的能力
由誰進行測試?開發部門/測試部門? - 應該由開發部門進行單元測試!
- 測試部門進行單元測試的問題:代價高,人手不足,耽誤了測試部門對其他測試的準備工作。
- 由開發部門進行單元測試的問題:擔心影響開發進度,程序員不習慣做單元測試,測試自己編寫的代碼,難于保證測試的效果。
- 無論由哪個部門做單元測試,都要面對一些問題,但開發部門所面對的問題可以借助工具來解決,而由測試部門進行單元測試,要么無法真正實施,要么代價昂貴。
由測試部門來單元測試成本昂貴? - 需多次重復理解程序
- 反復溝通需要大量時間成本
- 不利于發揮單元測試對代碼結構的約束機制
- 耽誤測試部門對其他測試的準備工作
- 即使測試部門人手充裕,僅僅從效益來考慮,也不應該由測試部門進行單元測試。如果測試部門本來就人力不充裕(進行單元測試的人員需具備編碼能力),勉強由 測試部門進行單元測試,結果往往是----沒有結果。
由開發部門進行單元測試能保證測試效果嗎? - 程序員測試自己編寫的代碼,往往只考慮“正常狀況”,這當然會影響測試效果。但如果所用的單元測試工具能夠統計各種白盒覆蓋率,就能檢查測試效果。當然, 只做到這一點還是不夠的,因為白盒覆蓋具有逾后逾難的特點,達到一定的覆蓋率后,覆蓋率的提升會很困難。如果測試工具功能足夠強大,能提供工具幫助用戶快 速地設計測試用例,達到完整的白盒覆蓋,那么測試效果就能得到完全的保證。
- 實際上,如果沒有充分的統計數據,沒有達到足夠的測試完整性,那么由誰做單元測試,效果都不能保證。
邊編碼邊測試會影響編碼進度嗎? - 傳統的單元測試是很費時費力的工作,主要時間消耗在于:編寫測試代碼、設計測試用例,如果開發工具能自動生成測試代碼,并且具有快速設計測試用例的功能, 那么測試費時就很少;另一方面,如果測試工具還能提供數據,幫助程序員整理編程思路、快速發現錯誤,更高效地調試,那么就能大量提高開發效率,抵銷測試所 消耗的時間,不但不會影響編碼進度,甚至加快編碼進度。
實施單元測試需要改變開發流程嗎? - 邊開發邊測試,單元測試是編碼行為而不是測試行為,測試代碼看作是項目代碼的一部分,程序員提交產品代碼時也要提交測試代碼和測試報告,其他流程可以不作 任何改變。
- 另一方面,在充分單元測試的基礎上,由于具有高質量的局部代碼,良好的整體代碼結構,保證了代碼的可擴展性和可復用性,同時,自動回歸測試支持對代碼的頻 繁修改而不用擔心引入新的錯誤,因此,開發流程自然會變得敏捷,可以適應頻繁變化的需求,使系統分析、架構設計和后期測試的壓力減輕,自然而有效地改進了 開發流程。
單元測試測試哪些代碼? - 單元測試通常不測試很簡單的代碼,一般也不測試“邊界代碼”。很簡單的代碼容易理解,例如Get/Set函數,這里解釋一下“邊界代碼”。“邊界代碼”是 指用于與外部系統交互的代碼,例如用于處理用戶界面的代碼。數據庫、文件、網絡都可以看作是外部系統,用于讀寫數據庫或文件、或訪問網絡的代碼也可以看作 是“邊界代碼”,這類代碼應該獨立出來,可以進行單元測試,但對這些代碼的單元測試通常不能自動驗證預期輸出,而是需要人工察看。編程時,不要把普通代碼 與“邊界代碼”混在一起,例如,不要把各種運算直接寫在界面類中,做到了這一點,絕大多數代碼都可以進行單元測試。
實際工作中,單元測試能實現什么程度的測試覆蓋? - 單元測試的最低要求是100%語句覆蓋,這個覆蓋率還是不夠的,最好實現多種覆蓋的組全,比較理想的覆蓋率組合是:100%的語句、條件、分支、路徑覆 蓋,另外,測試工具最好還能自動生成邊界測試用例捕捉未處理特殊輸入形成的錯誤。在達到這種覆蓋之后,殘留的編碼錯誤可以幾乎說沒有了(設計方面的錯誤除 外,這些屬于集成或系統測試的范疇)。
單元測試如何改良項目代碼的整體結構? - 具有良好整體結構的代碼,應該符合“低耦合”的特性,即具有“可測性”。測試不具有“可測性”的代碼時一般會產生編譯錯誤,或者需要打樁才能測試,從而將 問題暴露出來。發現問題后,重構代碼、消除不當耦合一般不難,這種簡單的重構將有效地改良代碼的整體結構。
我希望依賴全自動的工具來完成單元測試,這一想法現實嗎? - 完全自動化是一個美妙的愿望,但由于單元測試的基本特性,完全自動化的單元測試是不現實的。
- 與其他不同,單元測試是“隔離”的測試,要求代碼具有可測性,一個項目甚至一個文件中,難免會有些影響可測性的代碼,編譯到這些代碼時常常會產生編譯錯 誤,因此,全自動的單元測試工具往往只能測試小部分代碼,即使使用某種技術手段屏蔽掉編譯錯誤,也得不償失,因為同時也屏蔽掉了改良代碼整體結構的寶貴機 會。如果采用自底向上的方式,一個一個文件測試,測試一個文件前,先將該文件加入測試工程并編譯,沒有編譯錯誤時再測試,這樣可以及時發現并消除不當耦 合,使代碼具有可測性,這種非全自動的方式,可以測試絕大多數代碼,也保證了代碼具有良好的整體結構。
- 另一方面,主要由測試工具自動生成測試用例來進行測試往往沒有實際意義,因為測試工具無法自動了解程序的功能,因此,自動測試用例通常只能發現異常之類的 極端錯誤,大多數一般錯誤都是無法發現的。測試工具最重要的不是自動生成測試用例,而是能提供快速建立和編輯測試用例的工具。
如果由開發部門實施單元測試,那么測試部門要做哪些工作? - 推動、組織單元測試的實施。單元測試既然叫做“測試”,開發部門常常認識不到其重要性和必要性,需要由測試部門推動和協助組織實施。
- 制定單元測試規范,培訓單元測試技術。
- 檢查、審核單元測試結果,保證單元測試的有效性。
五、單元測試工具 - 測試工具的分類和選擇
- Parasoft
- Compuware
- Rational
- AutomatedQA AQTime
- xUnit系列
- Visual Studio 2005
- Visual Unit
測試工具的分類和選擇 - 白盒測試工具
- 靜態測試工具
- 動態測試工具
- 黑盒測試工具
- 功能測試工具
- 性能測試工具
- 測試管理工具
- 其他測試工具
- 測試工具的選擇
白盒測試工具 - 白盒測試工具一般是針對代碼進行測試,測試中發現的缺陷可以定位到代碼級
- 靜態測試工具直接對代碼進行分析,不需要運行代碼,也不需要對代碼編譯鏈接,生成可執行文件。靜態測試工具一般是對代碼進行語法掃描,找出不符合編碼規范 的地方,根據某種質量模型評價代碼的質量,生成系統的調用關系圖等。
- 動態測試工具與靜態測試工具不同,動態測試工具的一般采用“插樁”的方式,向代碼生成的可執行文件中插入一些監測代碼,用來統計程序運行時的數據。其與靜 態測試工具最大的不同就是動態測試工具要求被測系統實際運行。
黑盒測試工具 - 黑盒測試工具適用于黑盒測試的場合,黑盒測試工具包括功能測試工具和性能測試工具。
- 黑盒測試工具的一般原理是利用腳本的錄制(Record)/回放(Playback),模擬用戶的操作,然后將被測系統的輸出記錄下來同預先給定的標準結 果比較。黑盒測試工具可以大大減輕黑盒測試的工作量,在迭代開發的過程中,能夠很好地進行回歸測試。
- 黑盒測試工具的代表有Rational公司的TeamTest、Robot,Compuware公司的QACenter,另外,專用于性能測試的工具包括 有Radview公司的WebLoad、Microsoft公司的WebStress等工具。
測試管理工具 - 測試管理工具用于對測試進行管理。
- 內容:對測試計劃、測試用例、測試實施進行管理,對缺陷的跟蹤管理。
- 測試管理工具的代表有Rational公司的Test Manager、Compureware公司的TrackRecord,Mercury的TestDirector和Quality Center等軟件。
測試工具的選擇 - 功能
- 基本的功能
- 報表功能
- 測試工具的集成能力
- 操作系統和開發工具的兼容性
- 價格
- 連續性和一致性:
- 全盤考慮,分階段、逐步的引入測試工具
測試工具引入中的誤區分析 專題分析,引入哪些測試工具? 測試工具的培訓是一個長期的過程 系列的培訓和交流 沒有能夠形成一種機制讓測試工具真正能夠發揮作用 良好的測試工具使用環境 測試工具并不是策略 - 測試工具并不能教測試員如何測試。如果測試出現問題,則測試工具會加重問題。在實現測試過程自動化之前,應首先解決測試過程中的問題。
- 有些測試工具帶有測試策略的建議。但是這種建議很少能夠描述得很清楚,并不能針對具體情況,而且往往過于強調他們那種自動化測試的重要性。
- 工具是輔助性的,關鍵還是靠人的思想和行為!
Parasoft - Parasoft Jtest 代碼分析和動態類、組件測試
- Parasoft C++Test代碼分析和動態測試
- Parasoft .TEST代碼分析和動態測試
- Parasoft Insure++ 實時性能監控以及分析優化
- Parasoft CodeWizard代碼靜態分析
是第一個自動化Java單元測試工具。Jtest自動測試任何Java類或部件,而不需要您寫一 個測試用例、驅動程序或樁函數。只要點擊一個按鈕,Jtest自動測試代碼構造(白盒測試)、測試代碼功能性(黑盒測試)、維護代碼完整性(回歸測試)和 靜態分析(編程標準執行和指標度量)。不需要復雜的設置,Jtest能夠立即使用并指出問題。如果您使用“按合同設計”技術在代碼中加入描述信 息,Jtest能夠自動建立和執行測試用例驗證一個類的功能是否符合其功能描述。 Jcontract Java 實時性能監控以及分析優化 Parasoft C++Test 單元測試和靜態分析工具,自動測試C和C++類別、功能或組件,而無需編寫單個測試實例、測試驅動程序或樁調用。只需點擊按鈕,C++Test即會采用業 內編碼標準執行代碼的靜態分析,測試代碼構造(白盒測試),測試代碼功能性(黑盒測試),并保持代碼完整性(回歸測試)。 Parasoft .TEST 單元測試和靜態分析工具,自動測試寫在Microsoft?.NET框架的類別,而無需編寫單個測試場景或樁調用。只需點擊按鈕,.TEST即會 在.NET源代碼上自動執行完整系列的靜態和動態測試。.TEST RuleWizard性能通過圖形化表達希望.TEST在自動編碼標準執行過程中查找的模式,支持設計定制的編碼標準。 Parasoft Insure++ 一個自動化的內存錯誤、內存泄漏的精確檢測工具。Insure++能夠可視化實時內存操作,準確檢測出內存泄漏產生的根源。Insure++還能執行覆蓋 性分析,清楚地指示那些代碼已經測試過。將Insure++集成到您的開發環境中,能夠極大地減少調試時間并有效地防止錯誤。 Parasoft CodeWizard 高級C/C++源代碼分析工具,采用三百種以上行業相關的編碼準則,自動識別編譯器未檢測到的危險的編碼構造。CodeWizard可以容易地通過 RuleWizard性能,創建新定制的準則,或者抑制用于定制分析的準則。日常使用CodeWizard,可簡化代碼檢查,并使代碼更具可讀性和可維護 性。 Compuware白盒測試工具集 - http://www.compuware.com
- BoundsChecker C++,Delphi API和OLE錯誤檢查、指針和泄露錯誤檢查、內存錯誤檢查
- TrueTime C++ ,Java,Visual Basic 代碼運行效率檢查、組件性能的分析
- FailSafe Visual Basic 自動錯誤處理和恢復系統
- Jcheck M$ Visual J++ 圖形化的純種和事件分析工具
- TrueCoverage C++,Java,Visual Basic 函數調用次數、所占比率統計以及穩定性跟蹤
- SmartCheck Visual Basic 函數調用次數、所占比率統計以及穩定性跟蹤
- CodeReview Visual Basic 自動源代碼分析工具
Compuware DevPartner Studio 針對軟件開發小組使用 Microsoft Visual C++,Microsoft Visual Basic,Java,ASP 或 HTML 設計的一套緊密配合的調試,測試和管理工具。該產品結合了強大的錯誤檢測,性能分析,覆蓋率分析,需求管理,測試和發布工具與全面的工程跟蹤,錯誤管理, 任務管理和自動的工作流程。DevPartner Studio Enterprise Edition 通過提高軟件生產率,提高代碼質量,支持工作流以及通訊標準讓你對軟件工程有更多的控制權。 Win下最好的輔助調試工具。能夠幫你檢查內存泄漏,GDI泄漏,內存覆蓋,數組越界,系統API調用參數是否合適。還能profile,對你的程序的運 行時間進行分析,每個函數占用多少運行時間,每一行占用多少運行時間,幫你找出時間的瓶頸。 Rational - Rational Purify
- Rational Quantify
- Rational PureCoverage
- IBM Rational PurifyPlus
Rational Purify 面向VC, VB或者Java開發的測試Visual C/C++ 和Java代碼中與內存有關的錯誤,確保整個應用程序的質量和可靠性。在查找典型的Visual C/C++程序中的傳統內存訪問錯誤,以及Java中與垃圾內存收集相關的錯誤方面,Rational Purify可以大顯身手。Rational Robot的回歸測試與Rational Purify結合使用完成可靠性測試。 網址:http://www-306.ibm.com/software/rational/ Rational Quantify 面向VC、VB 或者Java開發的測試性能瓶頸檢測工具,它可以自動檢測出影響程序段執行速度的程序性能瓶頸,提供參數分析表等等直觀表格。幫助分析影響程序短執行速度 的關鍵部分。 網址:http://www-306.ibm.com/software/rational Rational PureCoverage 面向VC、VB或者Java開發的測試覆蓋程度檢測工具,它可以自動檢測你的測試完整性和那些無法達到的部分。作為一個質量控制工程,可以使用 PureCoverage在每一個測試階段生產詳盡的測試覆蓋程度報告。 網址:http://www-306.ibm.com/software/rational/ IBM Rational PurifyPlus 一套完整的運行時分析工具,旨在提升應用的可靠性和性能。包括Purify、Quantify、PureCoverage。 AutomatedQA AQTime AutomatedQA AQTime是軟件項目的測試工具,能實時/靜態地分析軟件的執行效率和代碼性能,發現軟件項目客戶端和服務器段的瓶頸所在、內存泄漏、消耗資源的代碼及 未經驗證的算法。能夠分析Delphi/BCB/VC/VB/GCC等工具開發的軟件產品,此外,它有專門For VS.NET的版本。AQTime是專業Windows開發者在開發過程中消除臆測的完全方案,使開發者在完成項目時開發出堅如磐石的程序。通過 AQTime無可匹敵的報告系統和測試分析架構,開發這不僅可以得知其項目中確實存在bug和瓶頸,而且會知道具體到哪個模塊、類、線程、代碼行出了問 題,從而快速消除錯誤。 性能架構和內存分配調試器,適于Win32和.NET互聯程序。該工具可以集成到Microsoft Visual Studio .NET中,也可單獨使用。通過AQtime 4,您不僅可以發現程序瓶頸,還可以查找瓶頸來源。 AQtime 4是AutomatedQA的獲獎產品performance profiling和memory debugging工具集的下一代替換產品,支持Microsoft, Borland, Intel, Compaq 和 GNU編譯器。新版本結合了旗艦產品Aqtime和AQtime for .NET的所有優勢,前者主要面向Win32應用程序性能分析,而后者則是第一個Microsoft .NET平臺的性能和內存分配架構工具。 如同其先前產品一樣,AQtime 4可以為.NET和Win32程序生成全面細致的報告,從而幫助您輕松隔離并排除代碼中含有的性能問題和內存/資源泄露問題。 xUnit系列 目前的最流行的單元測試工具是xUnit系列框架,常用的根據語言不同分為JUnit(java),CppUnit(C++),DUnit (Delphi ),NUnit(.net),PhpUnit(Php )等等。該測試框架的第一個和最杰出的應用就是由Erich Gamma (《設計模式》的作者)和Kent Beck(XP(Extreme Programming)的創始人 )提供的開放源代碼的JUnit。 xUnit系列 - Aunit Ada http://www.libre.act-europe.fr
- CppUnit C++ http://cppunit.sourceforge.net
- ComUnit VB,COM http://comunit.sourceforge.net
- Dunit Delphi http://dunit.sourceforge.net
- DotUnit .Net http://dotunit.sourceforge.net
- HttpUnit Web http://c2.com/cgi/wiki?HttpUnit
- HtmlUnit Web http://htmlunit.sourceforge.net
- Jtest Java http://www.junit.org
- JsUnit(Hieatt) Javas cript 1.4以上 http://www.jsunit.net
- PhpUnit Php http://phpunit.sourceforge.net
- PerlUnit Perl http://perlunit.sourceforge.net
- XmlUnit Xml http://xmlunit.sourceforge.net
CppUnit測試觀念 測試的結果是程序直接監測的,而不是“通過人眼對屏幕上的輸出結果的觀測”。 cppunit并不推薦屏幕輸出,或者寫可視化的測試單元 測試的過程是自動化的,不需要人工的干預 cppunit推薦用大量典型測試數據進行回歸的方式 測試用例是安全可控的。如果一個測試用例錯誤或者發生了異常,那么應該記錄這個錯誤,并且去執行下一個用例,而不應該停下來。cppunit測試框架保證 了這一點。 單元測試是頻繁發生的,每天都進行。 由于測試案例的自動化,故此,在你的模塊發生了重要改變時(特別是設計上的重大變化/重構時), 你都應該馬上運行一遍所有的測試程序,以確認你的代碼沒有引入預期(或曾經出現過)的bug。你可以在準備吃飯的時候,啟動單元測試程序進行回歸。 單元測試的目的是產生高質量的單元(模塊)。從而減少系統集成(包括系統集成測試)的代價。 Visual Studio 2005 Team版的VS2005里面包含了完整的Test功能,具體有:Unit Test,WebTest和LoadTest.這一整套的測試基本涵蓋了軟件開發會使用到的測試功能. 我這里先從單元測試開始介紹(Unit Test).說起單元測試,很多使用.net進行開發的人員也許馬上就想起了NUnit,實際上它是個很好的工具,在VS2005出來之前,我也一直使 用.不過現在VS2005已經提供了與NUnit一樣,甚至還要強大的功能,我們又有什么理由不使用呢? 微軟因該說是很好的領會和貫徹了這個中國的經典儒家思想。Borland的Together好,.Net2005中就集成了了class designer,雖然說功能還不是很強大,同樣,在單元測試成為軟件開發中必不可少的環節而Nunit好評如潮的時,.Net2005中也加入了自己的 單元測試組件。 Visual Studio 2005 自動代碼生成,是現代的開發環境追求的目標之一,而visual stutio無疑是走在了業界的最前列。在.net 2005中可以在右鍵菜單中選擇unit test,而后針對該類的方法的單元測試的框架便自動生成,為開發者提供了很大的便利。 Visual Studio 2005 Visual Studio 2005 Visual Unit - 國產的單元測試工具,據說申請了多項專利,擁有一批創新的技術。
- VU目前版本適用于C++語言。
- 黑盒方面,可以輕松完成功能測試、邊界測試、速度測試,
- 白盒方面,可以輕松完成語句覆蓋、條件覆蓋、分支覆蓋、路徑覆蓋。這種空前的測試完整性,使代碼中的缺陷無所循形。
六、如何實施單元測試 - 學習基本理論
- 評估&選擇單元測試軟件
- 選擇范圍:靜態分析、動態分析、測試程序框架
- 開發平臺:
- VC6.0?VS2005
- QNX
單元測試系列講座 七、討論 2 CppUnit Framework 一、背景 - CppUnit 是個基于 LGPL 的開源項目,最初版本移植自 JUnit,是一個非常優秀的開源測試框架。
- CppUnit 和 JUnit 一樣主要思想來源于極限編程(XProgramming)。
- 主要功能就是對單元測試進行管理,并可進行自動化測試。
- “現象” ? 就應該學習使用這種技術
二、感性認識 - CppUnit安裝與使用方法
- VC6
- VS2005
- QNX
- CppUnit快速入門
CppUnit VC6.0安裝 - 重要參考:INSTALL-WIN32.txt
- 解壓cppunit-1.12.0.tar.gz
- Building:---------
* Open the src/CppUnitLibraries.dsw workspace in VC++. * In the 'Build' menu, select 'Batch Build...' * In the batch build dialog, select all projects and press the build button. * The resulting libraries can be found in the lib/ directory. - 注意:直接編譯會有錯誤
CppUnit VC6.0安裝 - 注冊插件
- At the current time, the only supported WIN32 platform is
- Microsoft Visual C++. You must have VC++ 6.0 at least.
- Quick Steps to compile & run a sample using the GUI TestRunner:
- Open examples/examples.dsw in VC++ (contains all the samples). - VC7 will ask you if you want to convert, anwser 'yes to all'.
- Make HostApp the Active project - Compile - For Visual Studio 6 only: - in VC++, Tools/Customize.../Add-ins and macro files/Browse... - select the file lib/TestRunnerDSPlugIn.dll and press ok to register - the add-ins (double-click on failure = open file in VC++).
- Run the project CppUnit VC 設置 - “Projects/Settings.../C++/C++ Language”頁選中“Enable RTTI ”
RTTI---Run-Time Type Information - 在“Projects/Settings.../C++/Code Generation”頁選擇“Use run-time library”中的內容:
Release版, 選擇"Mulithreaded DLL". Debug版, 選擇 "Debug Multihreaded DLL". - Project Settings/Post-Build step增加: $(TargetPath)
CppUnit VS2005安裝 - 1、 Open examples/examples.dsw in VC++ (contains all the samples).
VC7 will ask you if you want to convert, anwser 'yes to all'. - 2、解決方案上右鍵,批量編譯,選擇全部,編譯
- 3、錯誤:
#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version ("7.0") lcid("0") raw_interfaces_only named_guids 改為: #import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version ("8.0") lcid("0") raw_interfaces_only named_guids - 4、d:/cppunit-1.12.0/cppunit-1.12.0/src/msvc6/dsplugin/stdafx.h
(12) : fatal error C1189: #error : This add-in is for VC++ 6.0 ?only. 不用處理 CppUnit VS2005 向導 - 0. 下載 CPPUnitProjectWizard
- 1. 復制文件
CPPUnitProjectWizard.vsdir - 為向導命名 CPPUnitProjectWizard.vsz - 讓VS8知道從哪里找到向導 到您的Visual Studio 8安裝目錄下的 VSProjects 文件夾中 - 2. 把整個CPPUnitProjectWizard解決方案文件夾復制到您的Visual Studio 8安裝目錄下的VCWizards文件夾中。
比如,我放在c:/Program Files/Microsoft Visual Studio 8/VC/VCWizards/CPPUnitProjectWizard/CPPUnitProjectWizard 或者,也可以放在你想放置的其它地方,然后編譯CPPUnitProjectWizard.vsz,定義參數 ABSOLUTE_PATH Param="ABSOLUTE_PATH = c:/Program Files/Microsoft Visual Studio 8/VC/VCWizards/CPPUnitProjectWizard/CPPUnitProjectWizard" - 3. 該項目需要定義環境變量 CPPUNITDIR
比如,我的環境變量 %CPPUNITDIR% = D:/cppunit-1.12.0 最后,修改 環境變量 %PATH%,在PATH路徑中,增加 %CPPUNITDIR%/lib,以便程序加載時能找到 cppunit_dll.dll - 4. 在開發環境中,設置好Include/Lib路徑
%CPPUNITDIR%/Include %CPPUNITDIR%/LIB CppUnit QNX - 參考工程模板
- 修改buildcfg.bat
- Qnx的安裝環境設置
- QNXDISK:qnx安裝在的分區
- SUNYPRJPATH:工程根路徑
- 調用build.bat編譯
- 舉例說明
CppUnit快速入門 - CppUnit本身的測試
- Example0--快速入門
三、基本理論 - 什么是 UnitTest Framework
- 什么是 CppUnit
- CppUnit 架構
- 產品代碼與測試代碼關系
- Unit Test與 TDD(測試驅動開發)
- CppUnit的原理
什么是UnitTest Framework 單元測試框架是編寫和運行單元測試的軟件工具,用來構建測試、運行測試、報告測試結果 unit test famework 的歷史以及 CppUnit JUnit -> xUnit(含CppUnit ) xUnit 家族 Junit - The reference implementation of xUnit CppUnit - The C++ port of JUnit NUnit - The xUnit for .NET PyUnit - The Python version of xUnit MinUnit - minimal but functional C Languages unit test framework XmlUnit – for XML contents 什么是 CppUnit CppUnit是個基于 LGPL 的開源項目,最初版本移植自 JUnit ,是一個非常優秀的開源測試框架。CppUnit和 JUnit 一樣主要思想來源于極限編程(XProgramming)。主要功能就是對單元測試進行管理,并可進行自動化測試。 CppUnit 架構--- namespace CppUnit 架構--- key classes CppUnit 架構--- classes to collect test results CppUnit 架構--- outputter classes for printing test results 產品代碼與測試代碼關系 產品代碼和測試代碼的目錄結構示意圖 產品代碼與測試代碼關系 產品代碼與測試框架關系示意圖 Unit Test與 TDD(測試驅動開發) - 測試驅動開發精髓
- TDD循環
“Test twice, code once” - 測試兩次,編碼一次。 - 測試驅動開發的原則
測試驅動開發精髓 - 維護詳盡的程序員編寫的測試程序組
- 除非有相關的測試,否則代碼不應被加入產品(“極限編程”,因為測試是重要的,所以對幾乎所有代碼都要有測試)
- 測試先行
- 測試決定你需要寫的代碼
TDD循環 “Test twice, code once” - 編寫新代碼的測試,查看是否失敗
- 編寫新代碼,以最簡方式實現
- 再次測試是否成功,重構代碼
測試驅動開發的原則 - 先寫測試代碼,然后編寫符合測試的代碼。至少做到完成部分代碼后,完成對應的測試代碼;
- 測試代碼不需要覆蓋所有的細節,但應該對所有主要的功能和可能出錯的地方有相應的測試用 例;
- 發現 bug,首先編寫對應的測試用例,然后進行調試;
- 不斷總結出現 bug 的原因,對其他代碼編寫相應測試用例;
- 每次編寫完成代碼,運行所有以前的測試用例,驗證對以前代碼影響,把這種影響盡早消除;
- 不斷維護測試代碼,保證代碼變動后通過所有測試;
- 在編碼前:他可以強迫你對需求進行詳細的分析。
- 在編碼時:他可以使你對over coding保持警覺。
- 在重構時:可以確保新的設計能夠兼容舊版本的功能。
- 在團隊開發時:可以確保自己的單元是無誤的。
CppUnit的原理 - Test
- TestFixture
- TestCase
- TestSuite
- ASSERT
CppUnit的原理--- Test - //Test.h
- 測試類的抽象基類
- 規定了所有測試類都應該具有的行為
- 對應于Composite Pattern中的Component
CppUnit的原理--- TestFixture - //TestFixture.h
- 一個或一組測試用例的測試對象被稱為 Fixture
- Fixture就是被測試的目標
- 為一組相關的測試提供運行所需的公用環境
- 抽象類,用于包裝測試類使之具有setUp方法和tearDown方法。
CppUnit的原理--- TestCase - //TestCase.h,TestCase.cpp
- 多重繼承:
- TestCase : public TestLeaf, public TestFixture
- TestLeaf: public Test
- TestCase :對這個 Fixture 的某個功能、某個可能出錯的流程編寫測試代碼,這樣對某個方面完整的測試被稱為TestCase(測試用例)
CppUnit的原理--- TestCase步驟 - 對 fixture 進行初始化,及其他初始化操作,比如:生成一組被測試的對象,初始化值;( setUp ())
- 按照要測試的某個功能或者某個流程對 fixture 進行操作;
- 驗證結果是否正確;
對 fixture 的及其他的資源釋放等清理工作 ( tearDown()) 運行時 CppUnit 會自動為每個測試用例函數運行 setUp,之后運行 tearDown,這樣測試用例之間就沒有交叉影響 CppUnit的原理--- TestCase注意點 - 可以自動執行,不用人手操作。
- 自動返回測試結果。
- 絕對的獨立,不能與其他TestCase有任何聯系。就算測試同一個函數的不同功能也需要分開。每個TestCase可以說是一個孤島。
- 例如
CppUnit的原理--- TestCase例子 CppUnit的原理--- ASSERT - CPPUNIT_ASSERT(condition):判斷condition的值是否為 真,如果為假則生成錯誤信息。
- CPPUNIT_ASSERT_MESSAGE(message, condition):與CPPUNIT_ASSERT類似,但結果為假時報告messsage信息。
- CPPUNIT_FAIL(message):直接報告messsage錯誤信息。
- CPPUNIT_ASSERT_EQUAL(expected, actual):判斷expected和actual的值是否相等,如果不等輸出錯誤信息。
- CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual):與CPPUNIT_ASSERT_EQUAL類似,但斷言失敗時輸出message信息。
- CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta):判斷expected與actual的偏差是否小于delta,用于浮點數比較。
- CPPUNIT_ASSERT_THROW(expression, ExceptionType):判斷執行表達式expression后是否拋出ExceptionType異常。
- CPPUNIT_ASSERT_NO_THROW(expression):斷言執行表達式expression后無異常拋出。
四、 核心內容 - 測試對象(Test,TestFixture,...)
用于開發測試用例,以及對測試用例進行組織管理 - 測試結果(TestResult)
處理測試用例執行結果, Observer Pattern - 測試結果監聽者(TestListener)
TestListener作為TestResult的觀察者,擔任實際的結果處理角色 - 結果輸出(Outputter)
將結果進行輸出,可以制定不同的輸出格式 - 對象工廠(TestFactory)
用于創建測試對象,對測試用例進行自動化管理 - 測試執行體(TestRunner)
用于運行一個測試 核心內容 ---Test - 所有測試對象的基類
- CppUnit采用樹形結構來組織管理測試對象,類似于目錄樹
組合設計模式(Composite Pattern),Test的兩個直接子類TestLeaf和TestComposite分別表示“測試樹”中的葉節點和非葉節點,其中 TestComposite主要起組織管理的作用,就像目錄樹中的文件夾,而TestLeaf才是最終具有執行能力的測試對象,就像目錄樹中的文件。 Test最重要的一個公共接口為: virtual void run(TestResult *result) = 0; 其作用為執行測試對象,將結果提交給result。 在實際應用中,一般不會直接使用Test、TestComposite以及TestLeaf,除非要重新定制某些機制。 核心內容 ---TestFixture 用于維護一組測試用例的上下文環境 在實際應用中,經常會開發一組測試用例來對某個類的接口加以測試,而這些測試用例很可能具有相同 的初始化和清理代碼。為此,CppUnit引入TestFixture來實現這一機制。 TestFixture具有以下兩個接口,分別用于處理測試環境的初始化與清理工作: virtual void setUp(); virtual void tearDown(); 核心內容 ---TestCase 測試用例,從名字上就可以看出來,它便是單元測試的執行對象。 TestCase從Test和TestFixture多繼承而來,通過把Test::run制定成模板函數(Template Method)而將兩個父類的操作融合在一起 這里要提到的是函數runTest,它是TestCase定義的一個接口,原型如下: virtual void runTest(); 用戶需從TestCase派生出子類并實現runTest以開發自己所需的測試用例。 核心內容 ---TestSuit 測試包,按照樹形結構管理測試用例 TestSuit是TestComposite的一個實現,它采用vector來管理子測試對象(Test),從而形成遞歸的樹形結構。 核心內容 --- TestCaller TestCase適配器(Adapter),它將成員函數轉換成測試用例 雖然可以從TestCase派生自己的測試類,但從TestCase類的定義可以看出,它只能支持一個測試用例,這對于測試代碼的組織和維護很不方便,尤 其是那些有共同上下文環境的一組測試。為此,CppUnit提供了TestCaller以解決這個問題 TestCaller是一個模板類,它以實現了TestFixture接口的類為模板參數,將目標類中某個符合runTest原型的測試方法適配成 TestCase的子類。 在實際應用中,大多采用TestFixture和TestCaller相組合的方式,詳見后面的 例子 核心內容 ---TestResult和TestListener 處理測試信息和結果 TestResult和TestListener采用了觀察者模式,TestResult維護一 個注冊表,用于管理向其登記過的TestListener,當TestResult收到測試對象(Test)的測試信息時,再一一分發給它所管轄的 TestListener。這一設計有助于實現對同一測試的多種處理方式。 核心內容 ---TestFactory 測試工廠 輔助類,通過借助一系列宏定義讓測試用例的組織管理變得自動化。參見后面的例子 核心內容 --- TestRunner 用于執行測試用例 TestRunner將待執行的測試對象管理起來,然后供用戶調用。其接口為: virtual void addTest( Test *test ); virtual void run( TestResult &controller, const std::string &testPath = "" ); 這也是一個輔助類,需注意的是,通過addTest添加到TestRunner中的測試對象必須 是通過new動態創建的,用戶不能刪除這個對象,因為TestRunner將自行管理測試對象的生命期 ??核心內容 ---例1 ??核心內容 ---例1 ??核心內容 ---例1 ??核心內容 ---例2 ??核心內容 ---例2 ??核心內容 ---例2 ??核心內容 ---例3 ??核心內容 ---例3 ??核心內容 ---例3 五、三個例子分析 Example 1: 自己寫測試框架 Example 2: 用CppUnit改寫Exp1 Example 3:完整的例子 ,用HelperMacros Example 1: 自己寫測試框架 Unit Test Frameworks ??步驟0:建立單元測試框架 ??步驟1:建立單元測試 (TDD第一次測試 ) ??步驟2:正確建立Book (TDD編寫一次) ??步驟3:再次測試 (TDD第二次測試) Exp1--- 0建立單元測試框架 Exp1--- 0建立單元測試框架 Exp1--- 0建立單元測試框架 Exp1--- 1建立單元測試 (Test 1st) Exp1--- 1建立單元測試 (Test 1st) Exp1--- 1建立單元測試 (Test 1st) Exp1--- 3再次測試 (Test 2nd) Example 2: 用CppUnit改寫Exp1 ??1:使用CppUnit框架的TestCase替換自定義的UnitTest ??2 :如果需要運行多個測試而不是放在單個runTest()中,則需要引入TestFixture ??3 :使用 TestSuite, 把main()中的addTest()轉移到 suite()中 ??4 :由于對每個測試類都要重復編寫suite()靜態函數,容易出錯,所以使用Helper Macros來替換手工編寫suite()靜態函數,和注冊函數 Exp2--- 1使用TestCase Exp2--- 2使用TestFixture Exp2--- 2使用TestFixture Exp2--- 2使用TestFixture Exp2--- 2使用TestFixture Exp2--- 2使用TestFixture Exp2--- 3使用TestSuite Exp2--- 3使用TestSuite Exp2--- 4使用HelperMacros Exp2--- 4使用HelperMacros Example 4:完整例子 ??CppUnit Cookbook ??Example3-1 ??Example3-2 六、CppUnit源碼解讀 七、討論 |