單元測試細節

2021-04-09 08:51:44 字數 4565 閱讀 7295

功能測試

對於乙個**單元,首先要測試它的基本功能。功能就是在某種輸入時應該產生某種確定的輸出。對於乙個**單元,它的可能輸入通常是無窮的,顯然,把輸入的 所有可能取值都進行測試,是不可能也是無意義的,我們應該用一定的規則選擇有代表性的資料來建立測試用例。要考慮的輸入主要有三種:正常輸入,邊界輸入, 非法輸入,每種輸入還可以分類,也就是平常說的等價類法,每類取乙個資料作為輸入資料建立測試用例,如果測試通過,可以肯定同類的其他輸入也是可以通過 的。如果等價類的劃分是準確且完整的,並且每乙個等價類都進行了測試,那麼,可以說這個**單元經過了充分的測試。下面舉例說明: 

正常輸入

例如字串的trim函式,功能是將字串前後的空格去除,那麼正常的輸入可以有四類:前面有空格;後面有空格;前後均有空格;前後均無空格。

邊界輸入

上例中空字串可以看作是邊界輸入。

再如乙個表示年齡的引數,它的有效範圍是0-100,那麼邊界輸入有兩個:0和100。

非法輸入

非法輸入是正常取值範圍以外的資料,或使**不能完成正常功能的輸入,如上例中表示年齡的引數,小於0或大於100都是非法輸入,再如乙個進行檔案操作的函式,非法輸入有這麼幾類:檔案不存在;目錄不存在;許可權錯誤。

如果輸入有多個資料,還要考慮這些資料之間的關係,即等價類還要包括資料的組合。

要人工找出所有的等價類通常是很困難的,但使用vu,通常不需要這樣做,只要為容易想到的、比較典型的等價類建立測試用例就行了,後文會有進一步的論述。

從上述可以看出,測試用例編輯器可以適應很複雜的測試用例的編輯。只要乙個測試用例已編輯完畢,第二個及更多的測試用例就很簡單了:選定乙個現有的測 試用例,由系統自動拷貝,使用者再對部分數值進行修改就行了。由於各個測試用例之間的差別通常很小,這種方式可以很快建立測試用例集。

測試用例編輯器還具有**模式,很特殊的情況下,可以切換到**模式下直接編輯**。

白盒測試

這裡所說的白盒測試,是指針對程式的邏輯結構來設計測試用例進行測試。白盒測試用邏輯覆蓋率來衡量測試的完整性。邏輯單位主要有:語句、分支、條件、條件 值、條件值組合,路徑。語句覆蓋就是覆蓋所有的語句,其他類推。另外還有一種判定條件覆蓋,其實是分支覆蓋與條件覆蓋的組合,在此不作討論。跟條件有關的 覆蓋就有三種,容易混淆,解釋一下:條件覆蓋是指覆蓋所有的條件表示式,即所有的條件表示式都至少計算一次,不考慮計算結果;條件值覆蓋是指覆蓋條件的所 有可能取值,即每個條件的取真值和取假值都要至少計算一次;條件值組合覆蓋是指覆蓋所有條件取值的所有可能組合。迴圈結構一般不考慮迴圈的次數,而只考慮 至少執行迴圈體一次和不進入迴圈體兩種情況,即把迴圈結構看作具有進入迴圈和不進入迴圈兩個會支的分支結構。由於不同的覆蓋率具有不同的側重點,為了保證 充分的測試,最好是完成幾種覆蓋率的組合。vu選擇了四種覆蓋的組合作為白盒測試指標:語句覆蓋、條件覆蓋、分支覆蓋、路徑覆蓋。如果這四種覆蓋都達到了 100%,那麼,測試的完整性是非常高的,讀者可以比較一下,在使用vu之前,您的專案要求達到什麼樣的白盒覆蓋?實際上又能完成到什麼程度?

白盒測試與功能測試有什麼關係呢?可以說,如果功能測試是足夠充分的,那麼白盒測試就沒有必要,從等價類的角度來看,足夠充分是指,等價類的劃分是完 全正確的,並且所有的等價類都測試到了。如何衡量功能測試的完整性呢?人工審核是乙個方法,不過這種方式代價較高,並且仍然不能保證結果的準確性。難於衡 量測試的完整性是功能測試的主要缺陷,而白盒測試恰恰具有易於衡量測試完整性的優點,兩者之間具有極好的互補性。

在單元測試中,功能測試和白盒測試通常具有這樣的關係:如果功能測試足夠充分,那麼,所有可以覆蓋的白盒邏輯單位都已經覆蓋,剩下的是不可覆蓋的;反 過來說,如果有一些邏輯單位未覆蓋,並且不能證明該邏輯單位是不可覆蓋的,那麼,可以認為功能測試不完整:或者等價類的劃分不夠準確完整,或者有些等價類 未測試到。也就是說,白盒覆蓋指標可以衡量功能測試的完整性,依據某個未覆蓋的邏輯目標,可以發現遺漏的等價類。執行測試後,vu會自動統計白盒覆蓋狀 況,標示出未覆蓋的**、條件、分支及路徑,並且提供測試用例設計器來幫助設計可以覆蓋遺漏的邏輯單位的測試用例。只要有了第乙個測試用例,測試用例設計 器就能很好地工作。

前面說過,使用vu,能達到100%語句、條件、分支、路徑覆蓋。很多讀者會問,對於稍為複雜一點的程式,路徑就可能幾百上千條,100%覆蓋可能嗎?那要耗費多少資源?

任何程式,不管它有多複雜,都不可能脫離客觀規律和客觀實際。路徑是什麼?路徑是**的組合,就是程式可能的執行路線。對於乙個函式來說,只要輸入確 定了,程式的執行路線就確定了(區域性靜態變數是乙個特例,它實質上是全域性變數,只不過是區域性可見而已,因此,也應該看作是乙個輸入)。從等價類的角度來 看,乙個等價類裡所有可能取值,一般來說覆蓋的路徑是一樣的。我們可以大體上認為:程式的可覆蓋路徑的數量與等價類的數量基本相等。例如,乙個程式,功能 是輸入人民幣小寫數值,輸出大寫字串,它的路徑可能有幾百條,但是,我們簡單的想一下,就會發現等價類不會超過十個,因此,大體上可以說,可以覆蓋的路 徑不會超過10條。

至於語句、條件、分支,也可能有一些是不能覆蓋的,這些邏輯目標的處理要比路徑簡單得多。我們說達到100%語句、條件、分支、路徑覆蓋,是指覆蓋可以覆蓋的部分,並把不能覆蓋的部分識別出來並作適當的處理。

vu的測試用例設計器具有兩方面的功能:識別不可覆蓋的邏輯目標,為可覆蓋的邏輯目標設計測試用例。測試用例設計器的工作原理是:從現有的測試用例中 計算出乙個最接近於可覆蓋預期邏輯目標的用例作為近似用例,並生成修改提示,依據修改提示對近似測試用例的乙個或多個輸入資料(通常是乙個)進行修改,並 視需要修改預期輸出,即可獲得可以覆蓋預期邏輯目標的測試用例。修改提示的主要內容是已滿足條件和待滿足條件,已滿足條件是近似測試用例已經滿足的條件, 修改近似測試用例時要保證不破壞已滿足條件,待滿足條件是新的測試用例必須滿足的條件。如果待滿足條件與已滿足條件不衝突,則依據待滿足條件修改近似測試 用例獲得新的測試用例,如果衝突,則該邏輯目標是不可覆蓋的,如果條件提示難於理解,可以切換到**模式下,檢視程式邏輯。

不可覆蓋的語句或條件,一般屬於冗餘**,建議刪除。不可覆蓋的分支或路徑,則在邏輯結構圖中打上刪除標識,這種刪除不會影響**。

有讀者會問,如果幾百上千條路徑,要一條一條識別它能不能覆蓋,那可能嗎?這種擔心是不必要的。只要按照語句覆蓋、條件覆蓋、分支覆蓋、路徑覆蓋的順 序來完成邏輯覆蓋,工作量通常都很小,原因是可確認的不可覆蓋的路徑會自動剔除。例如,如果一條分支不可覆蓋,那麼所有「經過」這條分支的路徑也肯定不可 覆蓋,把一條分支刪除了,所有「經過」該分支的路徑都會自動刪除,所以,在完成語句、條件、分支覆蓋後(包括把不可覆蓋的分支刪除),路徑數量就不會是龐 大的了,未覆蓋路徑則更少。

對於複雜的程式,還可以在邏輯結構圖中遮蔽一些安全的分支結構。有一些**形成的分支結構,對其後的程式的邏輯並無影響。例如:

void find(cstring& str,

char ch,

int start=0,

int end=-1)

上列的if結構形成的分支結構只用於處理預設值引數,對後面的**邏輯無影響,因此是安全的。在邏輯結構圖中,與乙個複雜的分支結構並列的乙個或多個簡單 的分支結構,通常都是安全的,可以在邏輯結構圖中檢視各個分支結構對應的**以判斷該分支結構是否安全。安全的分支結構可以遮蔽,以便把注意力集中到值得 關注的部分。遮蔽安全的分支結構也會使路徑的數量大幅度減少。前面所說的人民幣小寫轉大小的程式,在刪除了不可覆蓋分支,遮蔽了安全的分支結構後,路徑只 剩下不到十條,與等價類的數量是接近的。

邊界測試

在測試用例部分已經說過,設計測試用例時要考慮邊界輸入和非法輸入,這裡統稱為特殊輸入,程式設計師在編寫**時也要考慮特殊輸入,要為特殊輸入編寫處理代 碼。在實際工作中,程式設計師沒有考慮到某些特殊輸入是很常見的,這也是程式錯誤的乙個重要**。不幸的是,如果編寫**和建立測試用例時都沒有考慮這些輸 入,那麼白盒覆蓋也不能自動發現,因為白盒覆蓋是以**為基礎的,如果相應的**根本不存在,白盒覆蓋當然不會告訴使用者「某某**未覆蓋」。

特殊輸入通常與資料型別有關,例如,如果乙個引數是指標,空指標就是乙個特殊輸入,對於乙個整數型別,最大值、最小值、0、1、-1都可以算是特殊輸 入;另一方面,當輸入特殊資料時,如果程式未作合適的處理,執行結果常常是產生異常。根據這兩個條件,如果預先為各個資料型別定義特殊值,然後由測試工具 自動生成測試用例,使用這些特殊值或其組合作為輸入資料進行測試,通常可以發現「未處理特殊輸入」而產生的程式錯誤,這就是邊界測試。

如果在邊界測試中發現了處理某些特殊輸入的**缺失,應補充這些**,並完成白盒覆蓋。

為了進一步說明測試完整性,舉個例子:假如乙個函式,大概有十個等價類,但這個數字並不是顯式的,測試人員比較容易想到的,可能只有五個,自己畫一下邏輯 結構圖,做一些**分析,也許又可以找到二三個,是不是齊全了呢?很難衡量。使用vu,設計測試用例的過程大體是這樣的:使用者為容易想到的五個等價類建立 測試用例,根據語句、條件、分支覆蓋,在測試用例設計器的幫助下,找到另兩個等價類,根據路徑覆蓋,又揪出了兩個很隱秘的等價類,實現了100%語句、條 件、分支、路徑覆蓋,最後,邊界測試又發現了乙個意料之外的等價類。當然,這些數字只是乙個示意,實現某某覆蓋的目的,並不在於覆蓋率,而在於盡可能找出 所有等價類。

如果針對**單元的測試完成了100%語句、條件、分支、路徑覆蓋,並且執行了邊界測試,雖然仍然不能證明所有的等價類都測試到了,但可以肯定的說, 已經達到了很高的測試完整性,區域性**中仍然含有錯誤的可能性很小,當然,設計上的錯誤除外,這不屬於單元測試的範疇。

回歸測試

在修改了**後,可以使用回歸測試,對選定的任何類或整個工程執行測試,以檢測修改是否破壞了現有**的功能。一般來說,修改了私有函式,要執行整個類的測試,修改了公有或保護函式,則要執行整個工程的測試。

單元測試 單元測試文章收藏

前言 前段時間公司計畫做自動化測試,自己也打算圍繞幾個點做相關調研,現在想想呢?其實對自動化測試的概念都還不是十分清晰,當時主要還是圍繞 單元測試 向qa小夥伴學習了一段時間,現由於公司重組,學習中斷,這裡簡單記錄一些單元測試好文,留待後續參考.什麼叫自動化測試?自動化測試覆蓋率?覆蓋率如何做到的?...

單元測試之Django單元測試

每個應用,自帶tests.py 整合在django的專案檔案裡,更多是開發人員寫django自動的測試執行 3.1 前後置方法執行特點 django.test.testcase類主要由前 後置處理方法和test開頭的方法組成 特點 繼承於django.test.testcase 測試用例都是test...

單元測試(三) 建立多執行緒單元測試

junit本是不支援多執行緒的,乙個單元測試case主程序跑完,其他new出來的執行緒都會gg思密達。此篇mark乙份在junit中執行多執行緒的方法。net.sourceforge.groboutils groboutils core 5test slf4j public class device...