一、單元測試方法
單元測試的對象是軟件設計的最小單位——模塊。單元測試的依據是詳細設描述,單元測試應對模塊內所有重要的控制路徑設計測試用例,以便發現模塊內部的錯誤。單元測試多采用白盒測試技術,系統內多個模塊可以并行地進行測試。
單元測試任務
單元測試任務包括:1 模塊接口測試;2 模塊局部數據結構測試;3 模塊邊界條件測試;4 模塊中所有獨立執行通路測試;5 模塊的各條錯誤處理通路測試。
模塊接口測試是單元測試的基礎。只有在數據能正確流入、流出模塊的前提下,其他測試才有意義。測試接口正確與否應該考慮下列因素:
1 輸入的實際參數與形式參數的個數是否相同;
2 輸入的實際參數與形式參數的屬性是否匹配;
3 輸入的實際參數與形式參數的量綱是否一致;
4 調用其他模塊時所給實際參數的個數是否與被調模塊的形參個數相同;
5 調用其他模塊時所給實際參數的屬性是否與被調模塊的形參屬性匹配;
6調用其他模塊時所給實際參數的量綱是否與被調模塊的形參量綱一致;
7 調用預定義函數時所用參數的個數、屬性和次序是否正確;
8 是否存在與當前入口點無關的參數引用;
9 是否修改了只讀型參數;
10 對全程變量的定義各模塊是否一致;
11是否把某些約束作為參數傳遞。
如果模塊內包括外部輸入輸出,還應該考慮下列因素:
1 文件屬性是否正確;
2 OPEN/CLOSE語句是否正確;
3 格式說明與輸入輸出語句是否匹配;
4緩沖區大小與記錄長度是否匹配;
5文件使用前是否已經打開;
6是否處理了文件尾;
7是否處理了輸入/輸出錯誤;
8輸出信息中是否有文字性錯誤;
檢查局部數據結構是為了保證臨時存儲在模塊內的數據在程序執行過程中完整、正確。局部數據結構往往是錯誤的根源,應仔細設計測試用例,力求發現下面幾類錯誤:
1 不合適或不相容的類型說明;
2變量無初值;
3變量初始化或省缺值有錯;
4不正確的變量名(拼錯或不正確地截斷);
5出現上溢、下溢和地址異常。
除了局部數據結構外,如果可能,單元測試時還應該查清全局數據(例如FORTRAN的公用區)對模塊的影響。
在模塊中應對每一條獨立執行路徑進行測試,單元測試的基本任務是保證模塊中每條語句至少執行一次。此時設計測試用例是為了發現因錯誤計算、不正確的比較和不適當的控制流造成的錯誤。此時基本路徑測試和循環測試是最常用且最有效的測試技術。計算中常見的錯誤包括:
1 誤解或用錯了算符優先級;
2混合類型運算;
3變量初值錯;
4精度不夠;
5表達式符號錯。
比較判斷與控制流常常緊密相關,測試用例還應致力于發現下列錯誤:
1不同數據類型的對象之間進行比較;
2錯誤地使用邏輯運算符或優先級;
3因計算機表示的局限性,期望理論上相等而實際上不相等的兩個量相等;
4比較運算或變量出錯;
5循環終止條件或不可能出現;
6迭代發散時不能退出;
7錯誤地修改了循環變量。
一個好的設計應能預見各種出錯條件,并預設各種出錯處理通路,出錯處理通路同樣需要認真測試,測試應著重檢查下列問題:
1輸出的出錯信息難以理解;
2記錄的錯誤與實際遇到的錯誤不相符;
3在程序自定義的出錯處理段運行之前,系統已介入;
4異常處理不當;
5錯誤陳述中未能提供足夠的定位出錯信息。
邊界條件測試是單元測試中最后,也是最重要的一項任務。眾的周知,軟件經常在邊界上失效,采用邊界值分析技術,針對邊界值及其左、右設計測試用例,很有可能發現新的錯誤。
單元測試過程
一般認為單元測試應緊接在編碼之后,當源程序編制完成并通過復審和編譯檢查,便可開始單元測試。測試用例的設計應與復審工作相結合,根據設計信息選取測試數據,將增大發現上述各類錯誤的可能性。在確定測試用例的同時,應給出期望結果。
應為測試模塊開發一個驅動模塊(driver)和(或)若干個樁模塊(stub),下圖顯示了一般單元測試的環境。驅動模塊在大多數場合稱為“主程序”,它接收測試數據并將這些數據傳遞到被測試模塊,被測試模塊被調用后,“主程序”打印“進入-退出”消息。
驅動模塊和樁模塊是測試使用的軟件,而不是軟件產品的組成部分,但它需要一定的開發費用。若驅動和樁模塊比較簡單,實際開銷相對低些。遺憾的是,僅用簡單的驅動模塊和樁模塊不能完成某些模塊的測試任務,這些模塊的單元測試只能采用下面討論的綜合測試方法。
提高模塊的內聚度可簡化單元測試,如果每個模塊只能完成一個,所需測試用例數目將顯著減少,模塊中的錯誤也更容易發現。
二、經驗總結
工廠在組裝一臺電視機之前,會對每個元件都進行測試,這,就是單元測試。
其實我們每天都在做單元測試。你寫了一個函數,除了極簡單的外,總是要執行一下,看看功能是否正常,有時還要想辦法輸出些數據,如彈出信息窗口什么的,這,也是單元測試,我們把這種單元測試稱為臨時單元測試。只進行了臨時單元測試的軟件,針對代碼的測試非常不完整,代碼覆蓋率要超過70%都非常困難,未覆蓋的代碼可能遺留大量的細小的錯誤,這些錯誤還會互相影響,當BUG暴露出來的時候難于調試,大幅度提高后期測試和維護成本,也降低了研發商的競爭力。能說,進行充分的單元測試,是提高軟件質量,降低研發成本的必由之路。
對于程式員來說,如果養成了對自己寫的代碼進行單元測試的習慣,不僅能寫出高質量的代碼,而且還能提高編程水平。
要進行充分的單元測試,應專門編寫測試代碼,并和產品代碼隔離。我們認為,比較簡單的辦法是為產品工程建立對應的測試工程,為每個類建立對應的測試類,為每個函數(非常簡單的除外)建立測試函數。首先就幾個概念談談我們的看法。
一般認為,在結構化程式時代,單元測試所說的單元是指函數,在當今的面向對象時代,單元測試所說的單元是指類。以我們的實踐來看,以類作為測試單位,復雜度高,可操作性較差,因此仍然主張以函數作為單元測試的測試單位,但能用一個測試類來組織某個類的所有測試函數。單元測試不應過分強調面向對象,因為局部代碼依然是結構化的。單元測試的工作量較大,簡單實用高效才是硬道理。
有一種看法是,只測試類的接口(公有函數),不測試其他函數,從面向對象角度來看,確實有其道理,不過,測試的目的是找錯并最終排錯,因此,只要是包含錯誤的可能性較大的函數都要測試,跟函數是否私有沒有關系。對于C++來說,能用一種簡單的方法區隔需測試的函數:簡單的函數如數據讀寫函數的實目前頭文件中編寫(inline函數),所有在源文件編寫實現的函數都要進行測試(構造函數和析構函數除外)。
什么時候測試?單元測試越早越好,早到什么程度?XP研發理論講究TDD,即測試驅動研發,先編寫測試代碼,再進行研發。在實際的工作中,能不必過分強調先什么后什么,重要的是高效和感覺舒適。從我們的經驗來看,先編寫產品函數的框架,然后編寫測試函數,針對產品函數的功能編寫測試用例,然后編寫產品函數的代碼,每寫一個功能點都運行測試,隨時補充測試用例。所謂先編寫產品函數的框架,是指先編寫函數空的實現,有返回值的隨便返回一個值,編譯通過后再編寫測試代碼,這時,函數名、參數表、返回類型都應該確定下來了,所編寫的測試代碼以后需修改的可能性比較小。
由誰測試?單元測試和其他測試不同,單元測試可看作是編碼工作的一部分,應該由程式員完成,也就是說,經過了單元測試的代碼才是已完成的代碼,提交產品代碼時也要同時提交測試代碼。測試部門能作一定程度的審核。
關于樁代碼,我們認為,單元測試應避免編寫樁代碼。樁代碼就是用來代替某些代碼的代碼,例如,產品函數或測試函數調用了一個未編寫的函數,能編寫樁函數來代替該被調用的函數,樁代碼也用于實現測試隔離。采用由底向上的方式進行研發,底層的代碼先研發并先測試,能避免編寫樁代碼,這樣做的好處有:減少了工作量;測試上層函數時,也是對下層函數的間接測試;當下層函數修改時,通過回歸測試能確認修改是否導致上層函數產生錯誤。
文章來源于領測軟件測試網 http://www.kjueaiud.com/