700 likes | 930 Views
第 8 章 測試與驗證 . 本章大綱. 8.1 軟體測試 8.2 動態測試 8.3 靜態測試 8.4 測試的實施 8.5 結語 . 學習目標. 瞭解軟體測試的原理及其限制 能區別軟體驗證所用的各種方法 能使用黑、白箱測試技術來產生測試案例 能使用靜態軟體驗證技術 能夠製作軟體測試計畫. 相關新聞報導. 奔騰臭蟲: 1994 年發行的 Intel Pentium 晶片,在浮點運算部份產生錯誤,晶片回收,代價: $475M
E N D
本章大綱 8.1 軟體測試 8.2 動態測試 8.3 靜態測試 8.4 測試的實施 8.5 結語
學習目標 瞭解軟體測試的原理及其限制 能區別軟體驗證所用的各種方法 能使用黑、白箱測試技術來產生測試案例 能使用靜態軟體驗證技術 能夠製作軟體測試計畫
相關新聞報導 奔騰臭蟲:1994年發行的Intel Pentium晶片,在浮點運算部份產生錯誤,晶片回收,代價:$475M 亞利安故障:1996年12月,亞利安5號火箭在發射後40秒爆炸,只因一個軟體元件發生意外,代價:$400M Therac-25意外:Therac-25是一套放射線治療儀器,由於一個軟體的故障,導致錯誤的X射線劑量被釋放出來,代價:人命一條
軟體測試(1/5) • 軟體測試有關的名詞 • 錯誤(error):錯誤是人所造成的。它的另一個同義詞是「失誤」(mistake)。人們在撰寫程式時,經常由於思慮不周或不小心,而發生錯誤。錯誤擴散:需求分析的錯誤在設計時被放大,進一步延續到編碼。 • 缺陷(fault):缺陷是錯誤的結果。更準確地說,缺陷是錯誤的外顯,存在於表達之中,「瑕疵」(defect)是它的同義詞,「臭蟲」(bug)也是。缺陷不易發現:不該有的東西突然出現比較容易發現,該有的東西沒有出現比較不容易發現。
軟體測試(2/5) • 故障(failure):當程式執行到缺陷的位置時,故障才會發生。不是所有的缺陷都會表現出故障的行為,故障只發生在可執行的程式碼中。有些缺陷只在特定的環境或時間才發生故障。 • 事件(incident):不是所有的故障都有明顯的症狀或可一眼看出。事件是故障所產生的症狀,讓用戶警覺到故障的發生。 • 測試案例(test case):每個測試案例都有一個代號與測試目的(說明其程式應有的行為) • I:輸入,S:狀態,O:期望的產出
軟體測試(3/5) • 軟體測試的應用主要有以下兩種: • 驗證(verification):檢驗某個階段的產品發展是否符合其早先的規範,亦即正確地建造產品。 • 確認(validation):檢驗某個開發完成的系統是否符合用戶的需求,亦即建造對的產品。 • 兩者間的關係如圖8.1所示。
圖8.1 驗證與確認之間的關係 Validation Verification
軟體測試(4/5) • 測試方法的分類 • 測試對象 • 黑箱測試(black-box testing):又稱為功能測試,其目的是驗證系統的功能是否與預期相符。 • 白箱測試(white-box testing):又稱為結構測試,其測試方法是根據程式內的結構設計案例,分別驗證其行為的正確性。 • 測試工具 • 測試可以執行在「機器」或「人」的身上。若是前者,我們就稱作動態測試(dynamic test),因為測試是藉由電腦動態執行過程中來驗證; • 反之,則稱為靜態測試(static test),因為沒有執行程式的過程,而是由人扮演機器的角色,利用邏輯推理與經驗來查找缺陷。
軟體測試(5/5) • 測試層級 • 單元測試(unit test):對象主要是副程式、模組或物件方法,其重點在於將該程式當作一個獨立個體加以測試,因此往往需要驅動程式(driver program)的配合,藉著呼叫該程式來執行特定的任務。 • 整合測試(integration test):整合測試的目的,是驗證單元之間的介面是否正確,彼此間的訊息傳遞是否無誤。整合的方法可以是漸進的,或者是大霹靂(big bang)一次性整合。 • 系統測試(system test):對象是完整的系統,此時的目的是要確認系統是否達到原始的設計目標。
動態測試(1/19) • 外部測試 • 從外部測試,意味著將軟體系統當作黑箱加以測試,以確認它是否符合系統當初的要求。 • 黑箱測試主要針對以下類型的缺陷: • 功能不對或遺漏。 • 有瑕疵的程式介面。 • 資料結構或外部資料存取的缺陷。 • 初始化和終止條件錯誤等各類型可由行為觀察到的缺陷。 • 重點在於驗證系統的功能(參考圖8.4),所以有時又稱為功能測試。
圖8.4 外部測試的資料選取範圍 實際表現 的行為 期望的 系統行為 測試案例來自這裡
動態測試(2/19) • 功能測試的策略: • 等類分割(equivalence partition) • 其基本假設是程式的輸入值,可被分成若干個等類集合,而每個等類集合所導致的系統行為表現相似。 • 因此,每個集合只需選取一個代表案例來測試,即等同於測試整個集合(如圖8.5 )。 • 當物件之間的關係具有對稱性(Symmetric)、傳遞性(Transitive)、反身性(Reflective),就存在等類關係。
動態測試(3/19) • 如何決定等類集合,並沒有嚴謹的方法。但是一般可依照下列原則決定: • 如果輸入要求是一個範圍,可以該範圍定義一個有效的等類集合與兩個無效的等類集合。 • 如果輸入要求需要特定的值,可以該值定義一個有效的等類集合與兩個無效的等類集合。 • 如果輸入要求代表集合的某個元素,可以該元素定義一個有效的等類集合與一個無效的等類集合。 • 如果輸入要求是布林值,可以該值的條件要求定義一個有效的等類集合與一個無效的等類集合。 • 例如:計算 [1,1024] 範圍內整數的開平方根 y=(x)1/2 • 合法範圍:1~1024 • 無效範圍:-∞~0, 1025~∞ • 測試值:-1, 4, 1025
動態測試(4/19) • 邊界值分析(boundary value analysis) • 邊界值分析要求測試案例必須落在等類集合的邊界,所以是一種改善等類分割的測試方法。 • 不僅注重輸入條件,也要求必須從輸出條件中導出測試案例。 • 邊界值分析的一般原則為: • 如果輸入條件以a和b為邊界範圍,則測試案例應包含:a、b、略大於a、略小於b的值。 • 如果輸入條件是一組值,測試案例應選擇最大值和最小值,還應當測試略大於最小值的值和略小於最大值的值。
動態測試(5/19) • 上述原則也適用於輸出條件。例如,若程式的計算結果落在60~80之間,則測試案例應包含能夠產生最大和最小輸出值的項。 • 如果程式的資料結構有預定的邊界(例如,陣列的大小為100),則要測試其邊界的資料項目。 • 例:開平方根邊界值測試資料:0,1,1024,1025
動態測試(6/19) • 因果圖(cause-effect graph) • 因果圖是一種網狀式的邏輯組合圖。其中節點代表物件(或概念),以圓形表示;節點之間的連結,代表物件間的因果關係,以連線表示。連結與連結之間,可以定義邏輯關係,如圖8.6所示。
AND OR NOT 圖8.6 ATM之因果圖表示法 列印『指令無效』 存款指令 列印『存款帳號無效』 提款指令 列印『提款帳號無效』 帳號有效 執行提款金額 交易金額有效 執行存款金額
動態測試(7/19) • 因果圖從需求規範而來,建立方法如下步驟: • 研讀系統之功能規範。 • 標記並編號所有的原因與結果。 • 將被編號的原因與結果繪製成圖上的節點;原因繪製在左手邊,結果繪製在右手邊。 • 繪製原因和結果之間的邏輯關係,用適當的連結將相關的節點連接起來。 • 若有需要,可增加額外的中間結點,來簡化圖的描述。
動態測試(8/19) • 決策表(decision table) • 決策表(如表8.1的範例)係以行的形式描述決策規則,其中條件欄描述各種輸入情況,而作用欄列出系統應執行的活動。 • 決策表的優點,是可以清楚地將系統的行為以條列方式表達,每一條規則說明了條件與動作(或作用)之間的關係,因此,從測試的角度來看,它是很好的測試案例指引;一條規則至少應指派一個或一個以上的測試個案。 • 決策表範例,如表8.1所示。
動態測試(9/19) • 內部測試 • 內部測試的意涵,是將程式打開深入檢查其內部結構,並藉由程式的執行結果,察看它是否滿足原始功能設計的要求。 • 對於測試者而言,由於程式的各部分細節可被察看並一覽無遺,因此,我們稱之為白箱測試。 • 白箱測試並沒有特定的缺陷對象要偵測。其基本精神是要確認程式的每一部分都符合預期,且可以被正確地執行。為了達到這個目的,它會是針對受測軟體內部的路徑、結構和實施細節來設計測試個案。 • 如圖8.7所示。
實際表現 的行為 期望的 系統行為 測試案例來自這裡 圖8.7 內部測試之資料選取範圍
動態測試(10/19) • 白箱測試流程如下: • 分析受測軟體(Software Under Test, SUT)的程式結構,辨認出其中的敘述(statements)、分支(branches)、條件(conditions)以及路徑。 • 根據事先定義之測試準則,產生能讓SUT執行所選取路徑的測試個案,以及期望的結果。 • 進行測試。 • 比較實際輸出與期望的輸出。 • 判斷SUT是否在該測試發揮適當的作用。
動態測試(11/19) • 控制流測試 • 敘述涵蓋(statement coverage) • 敘述涵蓋的準則,是產生足夠的測試案例,以便程式中的每個敘述,至少能被執行一次。 • 除非每個敘述被有效地執行,否則我們無法知道,是否哪一項敘述裡隱藏著缺陷。 • 敘述涵蓋的缺點是不夠周延。 • 分支涵蓋(branch coverage) • 分支涵蓋的準則,是程式中的每個分支敘述,至少能被一個測試個案執行過。 • 除非每個程式的分支都被有效地執行,否則無法判斷是否有缺陷隱藏在某個分支裡。
動態測試(12/19) • 條件涵蓋(condition coverage) • 條件涵蓋是分支涵蓋的延伸。 • 由於分支涵蓋只要求到各分支被執行,而並未考慮到分支的每一個條件是否都被驗證過,因此,就測試的角度來說,還是可能有隱藏的缺陷沒有被偵測到。 • 條件涵蓋進一步要求每一個布林運算式中個別的條件,都必須被測試過一次。 • 條件涵蓋測試的問題:測試資料量過大。 • 如果某個布林運算式有n個條件,對條件涵蓋來說,它將需要2n個測試案例。因此,只有當n(條件的數目)很小的時候,條件涵蓋才有可能被實行。
動態測試(13/19) • 路徑涵蓋(path coverage) • 雖然條件涵蓋考慮了各種條件的組合,但是範圍僅限於一個分支,並不包含多個分支的組合測試。從測試的角度來看,這樣仍有所不足(如圖8.9)。 • 要涵蓋程式所有的路徑,在實務上並不可行;折衷的辦法是選取獨立路徑,或依照迴圈複雜度(cyclomatic complexity)的要求加以測試。
動態測試(14/19) L: link 連結數目,N: node 節點數目,P: procedure 副程式數目 • 獨立路徑測試(independence path) • 獨立路徑是一條貫穿程式的路徑,其中至少包含一個不含在其它獨立路徑中的新節點。 • 獨立路徑測試是指程式中所有線性獨立的路徑,都至少被一個測試案例執行過。 • 迴圈複雜度或馬克比度量(McCabe’s metric)可用來計算一個程式中獨立路徑的數目。 • 迴圈複雜度可以當作分支涵蓋的測試案例數量下限。 • 參閱圖8.10。
動態測試(15/19) • 若控制流程只有單一入口與單一出口 • B: binary branch 二元分支 • 三元分支=兩個二元分支 • N元分支=N-1個二元分支
動態測試(16/19) • 迴圈複雜度與品質 • 馬克比度量還有另外一層意義,就是提供一個量化指標來估計:測試的困難度、程式的心理複雜度及解讀程式的困難度。這些困難會隨著分支以及迴圈的數目增加而增加。 • 根據非正式的觀察顯示,馬克比度量、程式碼中缺陷的數目,以及測試程式碼所花費的時間存在著相關性。 • 因此,馬克比度量可當作指引,聚焦在測試高風險或難以測試的區域;或當作衡量測試進展的客觀指標,以決定何時可以停止測試;也可以用來評估一個完整的測試所需要的時間和資源。
動態測試(17/19) • 迴圈複雜度與風險 • 根據軟體工程學院(SEI)的網站所公布的建議,迴圈複雜度與風險評估之間的關連大致可整理如表8.2所示。 • 迴圈複雜度的限制 • 迴圈複雜度所衡量的,是控制流的複雜性,不是資料的複雜性。 • 對於同樣數量的巢狀和非巢狀迴圈,雖然得到同樣的複雜度,但是深層的巢狀結構比非巢狀結構更難以理解。
動態測試(18/19) • 資料流測試 • 一支程式在接受輸入資料後,會進行一連串的計算,直到輸出最後的結果。 • 從輸入到輸出的一連串資料變化,即是所謂的資料流(dataflow)。 • 資料流測試的目的:驗證這些資料在程式中的運算是否正確。 • 資料流測試準則,例如: • 定義涵蓋(all-defs)。 • 使用涵蓋(all-uses)。 • 定義-使用鏈涵蓋(all-DU-chains):每一個定義-使用鏈都必須至少被執行一次
資料流測試案例 DEF(S)={X|在敘述S中被定義的變數} USE(T)={X|在敘述T中被使用的變數} a的定義-使用鏈:[a,2,5],[a,2,6],[a,6,8],[a,6,5] S: a = b + c; DEF(S)={a} USE(S)={b,c}
動態測試(19/19) • 衡量測試的品質——突變測試 • 創造出一定數量的突變程式,其中的每一支只有很小的改變,然後用原來的測試案例,對這些突變程式一一執行,並檢驗測試結果。 • 如果在測試過程中,至少存在一個測試案例,能使某支突變程式產生不正確的結果,則這支突變程式就會被宣告死亡(dead)或被殺死(killed)。 • 若所有測試案例都執行過了,而某支突變程式仍然活著,就意味著原先的測試案例還不夠周延。 • 儘管測試過程可以被自動化,但是數量龐大的突變程式使得實行上變得非常困難。
靜態測試(1/8) • 許多錯誤早在需求分析或設計階段時就已經產生,如果應用動態測試,則必須等到程式完成後才能執行。然而此時才發現錯誤,已經太晚且會增加許多成本。 • 靜態測試集合相關技能的軟體專家與顧客,透過一種名為複查(review)的會議,共同來檢查軟體開發階段所產生的各種文件。 • 複查的進行,從非常正式到重點式查核,可分為: • 夥伴檢查法(buddy checking)。 • 演練(walkthrough)。 • 流通式複查(review by circulation):傳閱加註意見。 • 審查(inspection)。
靜態測試(2/8) • 審查法(Inspection) • 首先由Michael Fagan於1970年代在IBM提出,起先用於檢查軟體的設計與程式碼的缺陷,而後延伸到整個產品的開發。 • 審查的典型流程通常分為五個階段: • 計畫(planning)/概述(overview):負責開發產品的人必須準備一份產品概述文件(如規格/設計/程式碼/計畫),整理後分給每個與會人員。 • 準備(preparation):成員開始瞭解文件的細節,並記錄相關疑點。
靜態測試(3/8) • 審查(inspection):依據錯誤檢查表,逐項審查文件,列出找到的缺陷類型。依照重要性順序將錯誤條列記錄下來(在此,先不要修正這些錯誤,以便集中精力在發現錯誤上),最後由主持人整理成一份報告。 • 重新修正(rework):解決所發現的問題與缺陷。 • 追蹤(follow-up):主持人必須確定每一個問題皆已經被解決。 • 審查會議應由常見錯誤檢查表所引導(如圖8.12),其目的是協助審查者,注意被審查對象是否有品質上的疏失。
靜態測試(4/8) • 審查法的關鍵成功因素,包括下列幾項: • 避免自我主義與人格特質的衝突。 • 議題的分離並避免偏離會議主題。 • 注意檢查列表的重要性。 • 審查小組的訓練。 • 管理階層的支持。
靜態測試(5/8) • 審查法優點: • 大量的缺陷在軟體開始測試之前就已經被發現(設計與程式碼審查)。 • 程式設計師的生產力愈高,花在模組測試上的時間就愈少。 • 審查過的產品被找出的缺陷較少。 • 缺陷在早期被發現可以節省相當大的成本。 • 審查法缺點: • 無法檢查產品與顧客真正需求的一致性 • 不能檢視非功能性的特徵,如效能、可用性等。
靜態測試(6/8) • 演練法(Walkthrough) • 演練是一種模擬測試的方法,藉由一組選定的任務(或測試案例),演練在該產品(或文件)執行時的情形,以驗證並評估其功能。 • 演練法通常會有軟體品管人員參與會議。 • 會議中可以討論有關缺陷的修正、軟體的架構等問題。
靜態測試(7/8) • 演練法雖然無標準的進行形式(參考表8.4),但是至少應在與會前,先將演練所需材料事先發布下去。內容應包含: • 使用者描述:包括用戶對電腦的使用經驗,以及任何系統設計者所做的假設。 • 系統描述:包括系統的操作,以及效能的描述。 • 任務描述:從使用者的觀點所完成的任務。 • 動作順序描述:系統所呈現的畫面,以及要完成某任務所需進行的動作。
靜態測試(8/8) • 自動化分析 • 靜態測試除了利用專家同儕的複核之外,亦可利用自動化工具來協助進行分析。 • 靜態分析器(static analyzer),可用於分析原始程式碼,透過解析程式的內容,找出可能發生、潛在的錯誤情境,以提醒品管人員或工程師注意。
測試的實施(1/12) • 軟體測試計畫 • 測試計畫可以是另外一份獨立的文件(如圖8.13),也可以在專案計畫書中,增加一個章節加以說明 • 何者較佳,取決於測試的工作量與複雜度 • 軟體測試是一個需要正視的議題。根據一般報告,在軟體專案中,測試所消耗的資源,並不少於軟體開發所用的。 • 唯有適當地計劃,才能讓軟體測試有限的資源,發揮最大的效益。