Presentation is loading. Please wait.

Presentation is loading. Please wait.

軟體工程第六版 第十三章 測試策略.

Similar presentations


Presentation on theme: "軟體工程第六版 第十三章 測試策略."— Presentation transcript:

1 軟體工程第六版 第十三章 測試策略

2 軟體測試的策略 軟體測試的策略將軟體測試案例設計方法整合到一系列規劃良好的步驟中,以得到成功的軟體建構。
策略提供一個路線圖(road map)以描述被導入做為測試一部分的步驟、這些步驟何時被計畫並著手進行,和需要多少努力、時間與資源。 任何測試策略必須要合併測試計畫、測試案例設計、測試執行和結果資料的蒐集與評估。

3 軟體測試的策略 一個軟體測試策略應該有足夠的彈性以促進某種客製化的測試方式。 Shooman討論這些議題時說道:
當計畫進展時,必須要夠嚴謹以促進合理的計畫與管理追蹤。 Shooman討論這些議題時說道: 測試是一種個人化的流程,而不同測試類型的數量變化就像發展方法一樣多。 多年來,我們防護程式設計的錯誤只是很小心的設計與靠程式設計師的智慧。 現代設計的技術(和正式的技術檢視)可以協助我們減少繼承程式碼而來的初期錯誤數量。 不同的測試方法正在開始群集它們自己到某些較為顯著的方式與哲學。 這些「方式與哲學」就是我們所稱的策略(strategy)。 第14章中會說明軟體測試的技術。 本章聚焦於軟體測試的策略。

4 快速瀏覽 它是什麼? 軟體被測試是要揭開在它設計與建構時所不經意產生的錯誤。 當你發展軟體測試策略時,這些與其他許多的問題都是要回答的。
它是什麼?  軟體被測試是要揭開在它設計與建構時所不經意產生的錯誤。 但是你要如何主導測試呢? 你應該為你的測試發展正式的計畫嗎? 你應該測試整個程式或只是其中的一小部分? 當你將新的元件加入一個大系統時,應該重做你已經導入過的測試嗎? 你何時應該涉及到顧客? 當你發展軟體測試策略時,這些與其他許多的問題都是要回答的。

5 快速瀏覽 誰完成它? 它為何重要? 軟體測試的策略是由專案經理、軟體工程師和測試專家所共同發展的。
誰完成它?  軟體測試的策略是由專案經理、軟體工程師和測試專家所共同發展的。 它為何重要?  測試時常要對比其他任何軟體工程活動投入更多的專案努力。如果它隨意地被導入,不但浪費時間與花費不必要的努力,甚至更糟的是未發現隱藏錯誤。因此,建立一套系統化策略的測試軟體似乎是合理的。

6 快速瀏覽 步驟為何?  測試從「小的」開始,並且進展到「大的」。由此我們意味著早期的測試聚焦於單一元件或一小群相關的元件,並且應用測試揭發資料和已經含括於元件中的處理邏輯錯誤。在元件測試後,它們必須要整合,直到完整的系統被建構。此時,執行一系列高階的測試以在符合顧客的需求中發現錯誤。當錯誤揭發時,它們必須使用稱為除錯的流程診斷與修正。 工作產品為何?  測試規格(Test Specification)記載軟體團隊藉由定義一個描述整體策略、一個定義特定測試步驟和將被導入的測試程序的測試方式。

7 快速瀏覽 我如何確定我所做的是正確的?  藉由在測試之前檢視測試規格,你可以評估測試案例與測試任務的完整性。有效的測試計畫與程序將導致有條理地建構軟體,並在建構流程中每一個階段錯誤的發現。

8 13.1 軟體測試的策略方法 測試是可以預先計畫與系統化導入的一組活動。
軟體測試的樣版 - 我們可以放置特定的測試案例技術與測試方法的一組步驟 - 應該為軟體流程而定義。 許多軟體測試策略都提供軟體開發者樣版做為測試,且全部都具有下列的一般特性: 執行有效的測試,一個軟體團隊應該主導有效的正規技術檢視。 藉由執行此一檢視,許多錯誤將會在測試開始前就先被消除。 測試由元件層級開始,並「向外」朝著整個以電腦為基礎系統的整合。 不同的測試技術適用在不同的時間點上。 測試由軟體的開發者與獨立的測試群組所導入(對於大的計畫)。 測試與除錯是不同的活動,但是除錯必須被容納在任何的測試策略中。

9 軟體測試的策略範圍 軟體測試的策略必須要容納所必須要驗證的一小段原始碼已經正確地實作的低階測試,和以顧客的需求驗證主要系統功能的高階測試。
策略必須要對從業人士提供指導,並為經理人提供一組里程碑。 因為當截止日期的壓力開始上升時,測試策略的步驟就會出現,進展必須是可量測的,且問題必須要盡快浮現。

10 13.1.1 驗證與確認 軟體測試是廣泛主題中的一項元素,它時常是以驗證與確認(verification and validation, V&V)而被提到。驗證(verification)依據活動組以確保軟體正確地實作特定的功能。確認(validation)依據一個不同的活動組以確保已建構的軟體對顧客的需求是可追蹤的1。Boehm [BOE81] 以另一種方法說明: 驗證:我們正確地建構產品嗎? 確認:我們建構正確的產品嗎? V&V的定義含括許多在軟體品質保證(software quality assurance, SQA)中的活動。

11 驗證與確認的活動內容 驗證與確認含括廣泛的SQA活動,它們包括正式的技術檢視、品質與組態審核、效能監控、模擬、可行性研究、文件檢視、資料庫檢視、演算法分析、發展測試、可用性測試、限定條件(qualification)測試和安裝測試。 測試確實提供最後的堡壘,其中的品質可被評估,錯誤可以被揭發。 測試不應該被視為一張安全網。 當他們說:「你不能測試品質。如果在你開始測試前,它不在那裡的話,則在你完成測試後,它也不會在那裡。」 品質被併入到遍及整個軟體工程流程的軟體中。 適當的方法與工具的應用、有效的正式技術檢視和穩固的管理與量測,全部都會導致在測試期間被確認的品質。

12 品質保證的軟體測試 Miller陳述相關品質保證的軟體測試:
「程式測試的底層動機是以方法證實軟體的品質,此方法可經濟與有效地應用於大小規模的系統。」

13 13.1.2 軟體測試的組織 對於每一個軟體專案,測試的開始都有一個與生俱來的利益衝突發生。
已經建構軟體的人現在都被要求測試其軟體。這似乎對本身也無任何害處;畢竟,誰會比開發者更為瞭解此程式呢? 不幸地,這些相同的開發者在展示程式是沒有錯誤的時候,是存有既定利益的,它依照顧客的需求進行,且在期限與預算內完成。 這些利益的每一項都與測試是衝突的。

14 軟體測試的心理學觀點 從心理學的觀點來看,軟體分析與設計(連同編碼)是有建設性的工作。
軟體工程師分析、塑模,然後產生一支電腦程式與它的文件。 就像任何的建構者,軟體工程師對所建造的雄偉建築感到驕傲,並且斜眼瞄著任何一個試圖想要拆毀它的人。 當測試出現,就會有一個難以捉摸但很明確要「毀壞」軟體工程師所建造事物的企圖。 從建構者的觀點來看,測試可被視為(精神上)破壞性的。 建構者輕輕地踐踏,設計與執行的測試都展示出程式是可以工作的,而並非是揭發錯誤。 不幸地,錯誤還是會出現。 如果軟體工程師沒有發現它們,顧客則會找到的!

15 測試的錯誤推論 從前述的討論中經常會有一些錯誤的概念被錯誤地推論: 這些陳述的每一個都是不正確的。
軟體的開發者一點都不應該做測試。 軟體應該「丟過牆壁」給陌生人進行毫無仁慈的測試。 測試者只在測試的相關步驟開始時才參與專案。 這些陳述的每一個都是不正確的。 軟體開發者總是負責測試程式的個別單位(元件),以確保每個都實行功能或展現為它所設計的行為。 在許多情形中,開發者也導入整合測試 - 一個導致完整軟體架構建構(與測試)的測試步驟。 只有在軟體結構完成之後,一個獨立的測試群組才會參與。

16 獨立測試群組 獨立測試群組(independent test group, ITG)的角色是排除讓建構者測試已經建造事物的原有問題。
獨立測試除去其他方面可能的利益衝突。 ITG的員工是付錢請來發現錯誤的。 軟體工程師並不是將程式交給ITG就可安然脫身。 開發者與ITG在整個軟體工作期間緊密地工作在一起,以確保導入徹底的測試。 當測試導入時,開發者必須要有效地修正被揭發出的錯誤。 ITG是軟體開發專案團隊的一部分。他在分析與設計期間參與,並在整個大型專案內持續參與(計畫與指明測試程序)。 在許多情形中ITG將向軟體品質保證組織報告,因此達成某個程度的獨立性,這是做為軟體工程的一部分組織所不可能達到的。

17 13.1.3 傳統軟體架構的軟體測試策略 軟體流程可視為如圖13.1中所例舉的螺旋形。
最初,系統工程定義軟體的角色,並在資訊領域、功能、行為、效能、侷限因素和確認軟體建立的標準中導引軟體的需求分析。 沿著螺旋形向內移動,我們來到設計並抵達最後的編碼。 為了開發電腦軟體,我們沿著螺旋狀的流線型向內,每一次轉向都會降低抽象化的程度。

18 圖13.1 測試策略

19 軟體測試的策略 軟體測試的策略也可以視為螺旋形(圖13.1)的環境。
單元測試(unit testing)從螺旋形的漩渦開始,並聚焦在被實作成原始碼的每一個軟體單元(即元件)。 測試沿著螺旋形向外移動進展到整合測試(integration testing),在此的焦點為設計與軟體架構的建構。 朝著螺旋形向外轉一圈,我們遇到確認測試(validation testing),在此建立做為軟體需求分析一部分的需求對照著已經建構的軟體進行確認。 最後,我們來到系統測試(system testing),在此對軟體與其他的系統元素進行整體測試。 要測試電腦軟體,我們沿著螺旋形線流向外,每一次轉向都會擴大測試的範圍。

20 軟體工程環境中的測試步驟 軟體工程環境中的測試實際上是持續實作的一系列四個步驟。此步驟顯示於圖13.2中。
最初,測試聚焦在每一個個別的元件,以確保它是一個可適當運作的單元。 單元測試運用大量的測試技術,在元件的控制結構中操練指定的路徑,以確保完全地涵蓋與偵測出最多的錯誤。接著,元件必須要組裝或整合成完整的軟體套件(package)。 整合測試針對結合驗證與程式建構的雙重問題。 雖然操練指定程式路徑的技術可以確保主要控制路徑的涵蓋,聚焦在輸入與輸出的測試案例設計技術在整合期間則更為普遍。

21 軟體工程環境中的測試步驟 在軟體整合(建構)之後,一組高階的測試被導入。
確認標準(在需求分析期間所建立的)必須要被評估。 確認測試提供最後的保證使軟體符合所有功能的、行為的和效能的需求。 最後的高階測試步驟落在軟體工程的界限外,並進入電腦系統工程更為廣闊的環境中。 一旦確認,軟體必須與其他的系統元素結合(例如,硬體、人、資料庫)。 系統測試正確地驗證所有的元素網路(mesh),且整體的系統功能/效能是達成的。

22 圖13.2 軟體測試步驟

23 13.1.4 物件導向架構的軟體測試策略 物件導向的系統測試對軟體工程師呈現出一組不同的挑戰。
13.1.4 物件導向架構的軟體測試策略 物件導向的系統測試對軟體工程師呈現出一組不同的挑戰。 測試的定義必須要擴大以包括應用在分析與設計模型的錯誤發現技術(例如,正規的技術檢視)。 當它們被建構時,必須評估物件導向表示法的完全性與一致性。 單元測試喪失它的某些意義,且整合策略顯著地改變。 摘要來說,測試策略與測試戰術(第14章)必須要說明物件導向軟體的獨特性。

24 物件導向軟體的測試策略 就哲學上而言,物件導向軟體的整體策略在哲學上與應用到那傳統架構的是同一個,但在方式上有所不同。
由「測試小的」開始並向外進行到「測試大的」。 然而,我們聚焦於從「測試小的」個別模組(傳統的觀點)轉變成為一個含括屬性和隱含著通訊與協同合作的操作類別上。 當類別被整合進入一個物件導向的架構中時,一系列的回歸測試會執行,以找出類別間通訊與協同合作上的錯誤,和由於新類別(元件)加入所造成的副作用。 最後,對整個系統進行測試以確保能找出需求上的錯誤。

25 13.1.5 測試完成的標準 在軟體測試討論時,都有一個典型的問題會出現:
我們何時做測試?   我們如何知道我們已經做了充分的測試? 很不幸地,對這個問題沒有一定的答案,但是有一些務實的回應和在經驗指導下的初期嘗試。 對此問題的一個回應是:你從不做測試;只要很簡單地將你(軟體工程師)的負擔轉嫁給你的顧客身上。 每次顧客/使用者執行一支電腦程式時,此程式就正被測試中。 此一嚴肅的事實強調其他軟體品質保證活動的重要。 另一個回應是(有點挖苦,但仍然是正確的):當你耗費掉所有的時間,或是你花費掉所有的金錢後,你就做完測試了。

26 基於統計標準的回應 軟體工程師需要更多嚴格的標準以決定何時已經執行了充分的測試。 Musa與Ackerman建議的一種基於統計標準的回應:
「不,我們絕對不可能確信軟體永遠不會失敗,但相對於理論上可靠的與實驗上確認的統計模型,我們已經執行了充分的測試而有百分之95的把握說出在一個可能被定義環境中的1000個CPU小時內沒有失誤的機率至少為0.995。」 以統計塑模與軟體可靠度理論,軟體失敗(在測試期間所揭發)的模型可被發展成為執行時間的函式。

27 13.2 策略議題 如果沒有針對一系列優先性的(overriding)問題,即使是最好的策略都會失敗。
Tom Gilb主張如果要實作成功的軟體測試策略,必須要針對以下的問題: 在測試著手很早之前,採用可量化的方法指明產品的需求。 雖然測試的壓倒性目標是找出錯誤,一項好的測試策略也可評估其他的品質特性,如可攜性、可維護性和可用性(第15章)。這些應該被量測,使測試的結果不會含糊不清。 明確地說明測試的目標。測試的特定目標應該以可測量的項目名稱來陳述。 例如,測試有效性、測試範圍、失敗平均時間、發現和修正缺點的成本、剩餘的缺點密度或發生的次數和每次回歸測試的測試工作小時等,都應在測試計畫中說明。

28 實作成功軟體測試策略的議題 瞭解軟體的使用者,並對每一種使用者類型發展基本資料(profile)。
描述使用者每個類別互動情境的使用案例,藉由聚焦在產品實際使用的測試,可以降低整體測試的投入。 發展一個強調「快速循環測試(rapid cycle testing)」的測試計畫。 Gilb推薦一個軟體工程團隊的「學習對顧客有用的快速循環測試(2%的專案投入),至少是實地「可試驗的(trialable)」,功能性和/或品質改進的遞增。 從這些快速循環測試所產生的回饋可用來控制品質水準和相對應的測試策略。

29 實作成功軟體測試策略的議題 建立可設計成自我測試「強韌的」軟體。 使用有效的正規技術檢視做為測試之前的過濾器。
軟體應該使用反除錯(antibugging)(第13.3.1節)技術的方法設計。 即軟體應該有診斷某些類別錯誤的能力。 設計應該適應自動化測試與回歸測試。 使用有效的正規技術檢視做為測試之前的過濾器。 正規技術檢視可與測試一樣有效地揭發出錯誤。 因為這個原因,檢視能減少生產高品質軟體所必須要的測試投入。

30 實作成功軟體測試策略的議題 「只針對終端使用者需求的測試,如同基於室內設計師工作所做的地基、大樑和配管等工作的費用來檢測整個建築物。」
主導正規的技術檢視以評估測試策略與測試案例本身。 正規技術檢視可以揭發測試方法中的不一致性、疏忽和較為公開的(outrighter)錯誤。 這將節省時間並改善產品品質。 為測試流程發展持續改善的方式。此一測試策略應該被量測。 在測試期間所蒐集的度量(metrics)應該做為軟體測試中統計流程控制方法的一部分。 「只針對終端使用者需求的測試,如同基於室內設計師工作所做的地基、大樑和配管等工作的費用來檢測整個建築物。」 - Boris Beizer

31 13.3 傳統軟體的測試策略 有許多的策略可利用來測試軟體。
在極端的狀況,軟體團隊可以等到系統完全建構後,然後再對整個系統導入測試,希望能找到錯誤。 雖然很吸引人,但這種方式完全沒有用。 它的結果是造成充滿錯誤的軟體,並且使顧客與終端使用者感到失望。 在另一極端狀況,無論何時系統的任何一部分被建構完成後,軟體工程師可以每天導入測試。 這種方式,雖然對多數的人較不具吸引力,可是非常有效。

32 測試軟體的策略 不幸地,大多數的軟體開發者對於採用它顯得猶豫。能怎麼做呢? 大多數軟體團隊所選擇的測試策略都落在二個極端之間。
它採用漸進式的測試觀點,由個別程式單元的測試開始,再移轉到設計以促進單元整合的測試,且最後由操練所建構的系統做為結束。

33 13.3.1單元測試 單元測試(unit testing)聚焦於軟體設計最小單元的驗證投入
軟體元件或模組。 使用元件層級的設計描述做為指導,重要的控制路徑會被測試以揭發出模組邊界內的錯誤。 測試的相對複雜度和那些測試所揭發出的錯誤被單元測試所建立的侷限範圍所限制。 單元測試聚焦在內部的處理邏輯和元件界限內的資料結構。 這種測試型態可被平行地導入到多重的元件上。

34 單元測試的考量 發生做為單元測試一部分的測試以圖例的說明方式顯示於圖13.3中。 模組介面被測試以確保資訊適當地流入與流出測試中的程式單元。
區域資料結構被檢查以確保暫時儲存的資料在演算法執行所有步驟的期間維持它的完整性。 遍及控制結構的所有獨立路徑(基本路徑)被操練以確保所有在模組內敘述至少被執行過一次。 邊界條件被測試以確保建立用來限制或約束處理的界限可以適當地操作。 最後,所有的錯誤處理路徑也都被測試過。

35 圖13.3 單元測試

36 單元測試的考量 在任何其他的測試啟始前,橫跨模組介面的資料流向測試是必要的。
如果資料沒有正常的進入與離去,則所有的其他測試都是沒有意義的。 區域資料結構應該被操練,並且局部對全域資料的衝擊應該在單元測試期間確定(如可能的話)。 在單元測試期間,執行路徑的選擇測試是必要的工作任務。 測試案例應該設計以揭發由於錯誤的計算、不正確的比較或不適當的控制流向所導致的錯誤。

37 運算式中普遍的錯誤 在計算中更為普遍的錯誤還有: 誤解或不正確的算數優先順序(precedence) 混合模式的操作 不正確的初始值
精確度不準確 不正確的運算式符號表示。

38 比較與控制流向的測試 比較與控制流向彼此緊密地連接(即在比較後經常發生流向的改變)。測試案例應該揭發出錯誤,例如: 不同資料型式的比較
不正確的邏輯運算子或優先順序 當精準度錯誤使得等式不可能發生時的相等式預期 變數的不正確比較 不當的或不存在的迴圈中止 當遇到發散的(divergent)反覆時失敗地退出 不當地修正迴圈變數

39 邊界測試 邊界測試是最重要的單元測試任務之一。
軟體時常在它的邊界造成失敗。 當第n維陣列的第n個元素被處理時、當某個具有i回合的第i次重複被召喚時、當遇到最大或最小可允許的值時,錯誤時常會發生。 操練資料結構、控制流程和資料的值小於、正好或大於最大值與最小值等的測試案例很有可能揭發出錯誤。

40 反除錯的方式 當錯誤確實發生時,良好的設計要求錯誤的情況要預先考量,且設定重繞(reroute)的錯誤處理路徑或俐落地結束處理。Yourdon稱此方式為反除錯(antibugging)。 不幸地,有將錯誤處理納入軟體的趨勢出現,然而卻從不測試它。 一個真實的故事可以做為例子說明: 電腦輔助設計系統在合約的條件下發展。 在某個交易處理模組中,當召喚各種不同控制流程分支的一系列條件測試之後,在隨後的錯誤處理訊息中發生一個真實的笑話:錯誤!你應該沒有路徑可以到達這裡的。 這個「錯誤訊息」是在使用者訓練期間由顧客所揭發的!

41 應被測試的潛在錯誤 當錯誤處理被評估時,在這些應該被測試的潛在錯誤有: 難以理解的錯誤描述 所提到的錯誤沒有對應到所遇到的錯誤
錯誤條件造成作業系統的干預先於錯誤處理 例外條件處理是不正確的 錯誤的描述沒有提供充足的資訊,以協助錯誤起因位置的尋找。

42 單元測試程序 單元測試通常考慮成為編碼步驟中的一個附屬產物。
單元測試的設計可在編碼開始之前(一種喜好的機敏方式)或在原始碼產生之後可被實行。 設計資訊的檢視提供建立測試案例的指導,這些測試案例有可能揭發於先前討論的每種類型的錯誤。 每個測試案例應該與一組預期的結果結合在一起。

43 驅動程式和虛擬常式軟體 因為元件並不是一個單獨的(stand-alone)程式,必須為每一個單元測試發展出驅動程式(driver)和/或虛擬常式(stub)軟體。 單元測試環境於圖13.4中舉例說明。 在大多數的應用程式中,驅動程式如同一支「主程式」,它接受測試案例資料、傳送這些資料給元件(要被測試的),並列印出相關的結果。 虛擬常式(stub)做為替換從屬於(被呼叫)所要測試元件模組的一部分。 虛擬常式或「假副程式(dummy subprogram)」使用從屬模組的介面、可以做很小的數據操作、提供進入的驗證和回傳控制給接受的測試模組。

44 驅動程式和虛擬常式軟體 驅動程式與虛擬常式代表著額外的負擔。 當設計一個具有高度凝聚性的元件時,單元測試會被簡化。
即兩個都是必須要撰寫的軟體(正規設計的運用並不普遍),但並不與最終的軟體產品一起遞交。 如果驅動程式與虛擬常式保持簡單,實際上的負擔將相對很低。 不幸的是許多元件不能夠以「簡單」負擔的軟體進行充份的單元測試。 在此情況中,完整的測試可能被延期到整合的測試步驟中(驅動程式或虛擬常式也被使用)。 當設計一個具有高度凝聚性的元件時,單元測試會被簡化。 當只針對元件的某個功能時,測試案例的數目將會減少,並且錯誤可以更容易地預測與揭發。

45 圖13.4 單元測試環境

46 13.3.2 整合測試 一旦所有的模組都經過單元測試,軟體界中的生手(neophyte)會詢問一個表面似乎合理的問題:
「如果它們個別地都可以工作,而當我們將它們聚集在一起時,你為什麼對它們會工作產生懷疑呢?」 此問題是「將它們聚集在一起」 - 介接(interfacing)。 資料越過介面時可能會遺失; 一個模組可能對另一個具有疏忽、有害的影響; 當組合時,子功能可能無法產生所預期的主要功能; 個別可接受的不精準度,可能會被放大到無法接受的程度; 全域的資料結構會出現問題。 很可悲地,此列表不斷地一直繼續著。

47 整合測試的目標與方式 整合測試(integration testing)是建構軟體架構的一種系統化技術,同時主導測試以揭發與介接有關的錯誤。
其目標是拿取經過單元測試的元件,並建造一個由設計所要求的程式結構。 整合測試的方式: 非漸進式整合(nonincremental integration) 漸進式整合(incremental integration)

48 非漸進式整合 經常會有嘗試非漸進式整合(nonincremental integration)的趨勢,即使用「大爆炸(big bang)」方式建構程式。 所有的元件事先組合 整個程式做為一個整體進行測試 結果通常都是大混亂(chaos) 在整個計畫的龐大費用之下,當遇到一組錯誤時,改正會變得很困難,因為起因的隔離變得更為複雜。 一旦這些錯誤被改正後,新的一些問題又會出現,並且流程在似乎是永無止境的迴圈中繼續。

49 漸進式整合 漸進式整合(incremental integration)是大爆炸方式的對照。
程式以較小的增量進行建構與測試,其錯誤比較容易隔離與改正。 介面更為可能被完整的測試。 且可以應用系統化的測試方式。

50 由上而下的整合 由上而下整合的測試是軟體架構建構的漸進方式。
由主要的控制模組(主程式)開始,模組經由控制階層向下整合。 主要控制模組的從屬(和最終從屬)模組以深度優先(depth-first)或寬度優先(breadth-first)的方式被併入結構中。

51 深度優先整合 參考圖13.5,深度優先整合(deep-first integration)將整合程式結構中主要控制路徑上的所有元件。
主要路徑的挑選是有點隨意的,並依靠著應用程式獨有的特性。例如, 挑選左邊的路徑,元件M1、 M2、 M5將會首先整合。 接著,M8或(如果對M2適當地運作是有其必要時)M6將被整合。 然後,中間與右邊的控制路徑也會被建立出來。

52 圖13.5 由上而下的整合

53 寬度優先整合 寬度優先整合(breadth-first integration)水平地移動跨越結構,直接合併每一階層中從屬的所有元件。
圖中元件M2、M3、M4將首先整合。 接著到下一個控制階層的M5、M6等依次類推。

54 整合流程的步驟 整合流程以一系列的五個步驟實行: 主要控制模組用來做為測試驅動程式,並以虛擬常式替換所有直接從屬於主要控制模組的元件。
依據所挑選的整合方式(即深度或寬度優先),從屬的虛擬常式每次由一個真實的元件所取代。 當每一個元件被整合時,即導入測試。 每一組測試完成時,另一個虛擬常式就被真實的元件所取代。 導入回歸測試(稍後在本節中討論)以確保沒有引入新的錯誤。 此流程由第2步驟繼續,直到整個程式結構被建立為止。

55 由上而下的整合策略 由上而下的整合策略在測試流程早期就驗證主要的控制與決策點(decision point)。
在一個分解良好(well-factored)的程式結構中,決策會在階層中的上層發生,也因此會首先遇到。 如果主要的控制問題確實存在,儘早地確認是有必要的。 如果挑選深度優先的整合,軟體的完整功能可以被實作與展示。 例如,考慮典型的交易結構(第10章),其中一個複雜的連續互動輸入是經由進入路徑(incoming path)被要求、獲取與確認的。 進入路徑可以由上而下的方式整合。 在其他結構元素被整合以前,所有進入的處理(對隨後的交易派遣)可以被展示。 早期功能的能力展示是對開發者與顧客自信心的建立者。

56 由上而下測試策略的問題 由上而下的策略聽起來相對的不會很複雜,但在實務中可能會發生後勤的(logistical)問題。
當階層中位於底層的處理被要求能充分地測試較高的層級時,這些最常見的問題將會發生。 由上而下的測試開始時,虛擬常式取代底層的模組;所以在程式結構中,沒有顯著的資料能流往向上。

57 測試者執行時的選擇 測試者只剩下三個選擇: 延後許多測試,直到虛擬常式由真實的模組所取代, 開發模擬真實模組以實行限制功能的虛擬常式,
從階層的底部往上整合軟體。

58 三種測試方式的利弊 第一個方式(延後許多測試,直到虛擬常式由真實的模組所取代)會造成我們在相對應的特定測試與特定模組合併之間的一致上失去某些控制。 這在決定錯誤的原因會導致困難,並有違反由上而下這個方式所具有高度侷限性質的趨勢。 第二個方式是可行的,但是當虛擬常式變得越來越複雜時,會導致顯著的負擔。 第三個方式稱為由下往上的(bottom-up)測試,將在下一節中討論。

59 由下往上的整合 由下往上的整合測試(bottom-up integration testing),就如同它的名稱所隱含的,由自主的(atomic)模組開始建構與測試(即在程式結構中最底層的元件)。 因為元件由下往上整合,對從屬於某一階層元件所必要的處理總是可以利用的,並且可以消除對虛擬常式的需要。

60 由下往上的整合步驟 由下往上的整合策略可能以下列的步驟實作:
低層級元件被組合成實行特定軟體子功能的群集(clusters)(有時稱為構造(builds))。 撰寫驅動程式(測試用的控制程式)以協調測試案例的輸入與輸出。 測試群集。 移開驅動程式並將群集移往程式結構的上層組合。

61 由下往上的整合範例 整合採用圖13.6中所舉例說明的模式。 當整合往上移動時,對個別測試驅動程式的需要減少了。
元件被組合以形成群集1、2和3。 每一個群集使用一個驅動程式測試(以虛線的方塊顯示)。 在群集1與2中的元件是從屬於Ma的。 驅動程式D1與D2被移開,並且群集直接介接到Ma。 同樣地,群集3的驅動程式D3在與模組Mb整合前被移開。 最後,Ma與Mb將與元件Mc整合等。 當整合往上移動時,對個別測試驅動程式的需要減少了。 事實上,如果程式結構最高的二個階層是由上向下整合,驅動程式的數量實質上會減少,且群集的整合將有極大的簡化。

62 圖13.6 由上而下的整合

63 回歸測試 回歸測試(regression testing)每次增加一個新的模組成為整合測試的一部分,於是軟體就產生變化。
這些改變可能會對先前完美無瑕工作的功能造成問題。 在整合測試策略的環境中,回歸測試是重新執行某些已經導入確保改變不會蔓延出所不想要副作用的測試子集合。

64 回歸測試的導入方式 在更大範圍的環境中,成功的測試(任何種類)的結果是發現錯誤,且錯誤一定要被改正。
軟體無論何時被修改過,軟體組態(程式、它的文件或支援它的資料)的某些面向也會改變。 回歸測試是協助確保改變(由於測試或其他理由)不會引入非計畫中的行為或額外錯誤的活動。 回歸測試可用手動的方式導入,藉由重新執行所有測試案例的子集合或使用自動捕捉/再生(capture/playback)的工具。 捕捉/再生工具讓軟體工程師得以捕捉測試案例和接著的再生與比較的結果。

65 回歸測試套組 回歸測試套組(被執行的測試子集合)包含三種不同測試案例種類: 一個將操練所有軟體功能的代表性測試範本。
聚焦於改變時可能會被影響到軟體功能的額外測試。 聚焦在已經改變軟體元件的測試。

66 回歸測試的數量成長 當整合測試進行時,回歸測試的數量會成長的相當大。
回歸測試套組應該設計成只包括針對那些主要程式功能中每一個裡的一個或多個錯誤類別。 一旦改變發生,為每一個程式功能重新執行每一項測試是不務實且沒有效率的。

67 煙霧測試 煙霧測試(Smoke testing) 是當軟體產品正在發展時,一種普遍使用的整合測試方式。
它對時間緊迫的(time-critical)專案設計成步調固定(pacing)的機制,讓軟體團隊以頻繁的方式評估其專案。

68 煙霧測試的活動 煙霧測試方式含括下列的活動: 已經轉變成為程式碼的軟體元件被整合入「構造(build)」中。
構造包括所有的資料檔案、程式庫、可重複使用的模組和需要實作一個或多個產品功能的工程元件。 設計一系列暴露出更多錯誤的測試,以適當地實行功能來維持構造。 此意圖應該是揭發「顯現阻塞(show stopper)」的錯誤,它有最高的可能性會將軟體拋出計畫的時程之後。 構造每日進行煙霧測試,並會和其他的構造與整個產品(以它目前的形式)整合。 整合方式可能是由上而下或由下往上。

69 煙霧測試的特性 每日測試整個產品的頻繁度可能會讓一些讀者吃驚。 McConnell以下列的方式描述煙霧測試:
頻繁的測試可以給管理者與從業人員一個整合測試進展的實際評估。 McConnell以下列的方式描述煙霧測試: 煙霧測試應該從頭到尾地操練整個系統。 它不是一定要徹底的,但是它應該能夠暴露出主要的問題。 如果構造通過煙霧測試應該是完全足夠的,你可假設它是足夠穩定被更徹底地測試。

70 煙霧測試所提供的好處 當應用在複雜、時間緊迫的軟體工程專案時,煙霧測試提供一些好處: 整合風險降到最低。 終端產品的品質獲得改善。
因為煙霧測試每日導入執行,不相容性或其他顯現阻塞(show stopper)的錯誤早期就會被揭發。 當錯誤被揭發時,可以降低對時程可能的嚴重衝擊。 終端產品的品質獲得改善。 因為此方式是以建構(整合)為導向的,煙霧測試很可能揭發功能的錯誤和架構與元件層級設計的錯誤。 假如這些錯誤及早改正,就可產生更好的產品品質結果。

71 煙霧測試所提供的好處 簡化錯誤診斷與改正。 進展更為容易評估。
就像所有的整合測試方式,在煙霧測試期間揭發的錯誤可能會和「新的軟體增量」有關聯。   即增加構造的軟體可能是發現新錯誤的一個原因。 進展更為容易評估。 隨著每天的過去,更多的軟體已被整合,並且展示更多所執行的工作。 這會增進團隊的士氣,並帶給管理者一個表現進步良好的指示。 「將每日的構造視為專案的心跳。如果沒有心跳,專案就死了。」 Jim McCarthy

72 策略的選擇 對由上而下與由下往上整合測試的相對優點與缺點一直都有許多的討論(例如[BEI84])。
通常一個策略的優點很可能是另一個策略的缺點。 由上而下方式的主要缺點是對虛擬常式的需要,並且結合它們伴隨的測試變得困難。 結合虛擬常式的問題可藉由早期測試主要控制功能的優點而抵銷。 由下往上整合的主要缺點是「直到加入最後一個模組前,實體的程式不會存在。」 此一缺點可藉由較為容易的測試案例設計和沒有虛擬常式而調和。

73 策略的選擇-三明治測試 一個整合策略的挑選端視軟體的特性,有時也要依據專案的時程。
通常,程式的上層結構使用由上而下的測試,結合從屬層級由下往上測試的這種組合方式(有時稱為三明治測試(sandwich testing))或許是最好的折衷方案。

74 關鍵模組的特性 當整合測試導入時,測試者應該辨識出關鍵模組(critical modules)。 關鍵模組有一個或多個以下的特性:
針對某些的軟體需求 具有高控制層級(駐留在相對高層的程式結構中) 有複雜或錯誤的傾向 有明確的效能需求。 關鍵模組應該盡可能提早測試。 回歸測試應該專注於關鍵模組的功能。

75 整合測試文件 軟體整合的整體計畫和特定測試的描述被記錄在測試規格(test specification)中。 測試計畫描述整合的整體策略。
此文件包含測試計畫、測試流程,它是軟體流程的工作產品之一,並且成為軟體組態的一部分。 測試計畫描述整合的整體策略。 測試針對軟體特定的功能與行為的特性,區分成為階段(phases)與構造(builds)。 例如,電腦輔助設計系統(CAD)的整合測試可以區分為下列的測試階段: 使用者互動(命令挑選、畫出創作物、顯示的呈現、錯誤的處理與呈現)。 資料操縱與分析(符號產生、規模、旋轉、實際特性的計算)。 顯示處理與產生(二維顯示、三維顯示、圖形與圖表)。 資料庫管理(存取、更新、整合、效能)。

76 所有測試階段應用的標準測試 這些階段與子階段(括弧中所表示)的每一個描述軟體中大範圍的功能範疇,並且通常可與軟體架構中的特定領域相關。
程式的構造(模組的群體)被產生以對應到每一個階段。 下列的標準與對應的測試被應用到所有的測試階段: 介面的完整性(interface integrity) 當每個模組(或群集)併入結構中時,測試其內部與外部的介面。 功能有效性(functional validity) 設計用來揭發功能錯誤的測試應該要導入。 資訊內容(information content) 設計以結合區域或全域資料結構來揭發錯誤的測試應該導入。 效能(performance) 建立於軟體設計期間所設計來驗證效能界限的測試應該導入。

77 所有測試階段應用的標準測試 整合的時程、額外(overhead)軟體的發展和相關的主題也討論做為測試計畫的一部分。
建立每個階段開始與結束的日期,並為單元測試的模組定義「有效性視窗(availability windows)」。 對額外軟體(虛擬常式與驅動程式)的簡要描述專注在可能需要特別投入的特性上。 描述測試環境與資源。 不尋常的硬體組態、外來的模擬器和特別的測試工具或技術是許多主題中少數可能要討論的。 描述所需要完成測試計畫的詳細測試程序。 在每個整合步驟中的整合順序與相對應的測試也要描述。 一個所有測試案例(隨後的參考資料有註解)的列表和預期的結果也要包括在內。

78 所有測試階段應用的標準測試 一個真實測試結果的歷程、問題或特質都記錄在測試報告(test report)中,並可被附加到測試規格(test specification)裡。 如同一個軟體組態的所有其他元素,測試規格的格式可能裁製成軟體工程組織本身的需要。 一個整合策略(包含於測試計畫中)與測試細節(描述於測試流程中)是必要的成分,且必定要出現的。 「最好的測試者不是發現最多錯誤的人……最好的測試者是修補最多錯誤的人。」 Cem Kaner等

79 13.4 物件導向軟體的測試策略 測試的目標是運用於現實的一段時間中,以可管理的投入量,找出最大可能數量的錯誤。
雖然其基本目標沒有因為是物件導向的軟體而改變,但是物件導向軟體的性質改變了測試策略與測試戰術(tactics)。

80 13.4.1 在OO環境中的單元測試 當考慮物件導向軟體時,單元的概念改變了。 封裝(encapsulation)主導類別的定義。
每一個類別與每個類別的個例(物件)包裝了屬性(資料)和操縱這些資料的操作(功能)。 一個封裝的類別通常是單元測試的焦點。 類別中的操作是最小的可測試單元。 因為一個類別可以包含一些不同的操作,並且一個特定的操作也可能存在而成為許多不同類別的一部分。

81 改變應用到單元測試的戰術 不再以隔離的方式做單一操作(傳統單元測試觀點)的測試,但寧可做為類別的一部分。舉例說明,
考慮一個類別階層,其中X操作定義於父類別中,並由一些子類別所繼承。 每個子類別使用X操作,但它被應用於子類別所定義的私有屬性與操作的環境中。 因為在此環境中X操作的使用會有一些難以捉摸的各種變化,所以有必要在每一個子類別的環境中測試X操作。 這意味著在物件導向的環境中,以單獨的形式(傳統的單元測試方式)測試X操作通常是沒有效率的。 OO軟體的類別測試等同於傳統軟體的單元測試。 不像傳統軟體的單元測試,它傾向於聚焦在模組的演算法細節和流過模組介面的資料,OO軟體的類別測試是由類別所封裝的操作與類別狀態行為所驅動。

82 在OO環境中的整合測試 因為物件導向軟體沒有明顯的階層控制結構,傳統由上而下與由下往上的整合策略 (第13.3.2節)已沒有太多的意義。 每次整合一個操作到類別中常常是不可能的(傳統漸進的整合方式),因為「類別是由元件直接與間接的互動所組成的。」

83 OO系統整合測試的策略 OO系統的整合測試有兩種不同的策略: 以執行緒為基礎的測試(thread-based testing)
它整合必須回應一個系統的輸入或事件的類別組。 每個執行緒都是個別的整合與測試。 應用回歸測試以確保沒有副作用的發生。 以使用為基礎的測試(use-based testing) 它藉由測試使用少量(如果有的話)服務類別(server classes)的那些類別(稱為獨立類別(independent classes))開始系統的建構。 在獨立類別測試後,稱為依附類別(dependent classes)的下一層類別,則使用獨立類別進行測試。 依附類別的測試層級依序進行,直到整個系統建構完成為止。

84 驅動程式與虛擬常式的使用 當OO系統的整合測試導入時,驅動程式與虛擬常式使用也會改變。
驅動程式可使用來測試位於最底層的操作和整個類別群組的測試。 驅動程式也可取代使用者介面,使得系統功能性的測試可優先於介面實作前導入。 當類別之間的協同合作是必要時,但一個或多個協同合作類別尚未實作完成的情形下,虛擬常式可以使用。

85 群集測試 群集測試(cluster testing)是在OO軟體整合測試中的一項步驟。
協同合作的群集類別(由檢查CRC與物件關係模型所決定)藉由嘗試揭發協同合作中的錯誤而設計的測試案例進行操練。

86 13.5 確認測試 確認測試(validation testing)從整合測試的頂點(culmination)開始,當個別的元件被操練時,軟體被完整地組裝成為一個套件(package),且介面上的錯誤已被揭發與改正。 在系統層級的確認上,傳統與物件導向軟體之間的差別則會消失。 測試聚焦在系統中使用者可見的動作和使用者可辨識的輸出上。

87 確認 確認(validation)可用許多的方法定義,但是一個簡單的(雖然很粗糙)定義:
當軟體的功能可以用某個方法讓使用者合理地預期時,確認就是成功的。 強硬的(battle-hardened)軟體開發者可能會抗議:「誰或什麼是合理期望的仲裁?」 在軟體需求規格(software requirements specification, SRS)內-描述所有使用者可見的軟體屬性的文件,定義了合理的期望。 規格包含一個稱為確認標準(validation criteria)的部分。 包含在此部分的資訊形成確認測試方式的基礎。

88 確認測試標準 軟體的確認是經過一系列展示符合需求的測試而達成。一個測試計畫概述所導入測試的類別,而測試流程定義特定的測試案例。計畫與程序被設計出以確保所有的功能與需求被滿足、所有行為的特性都達成、所有效能上的需求都獲得、文件被更正和可用性與其他的需求都符合(例如,可傳輸性(transportability)、可相容性、錯誤回復、可維護性)。

89 確認測試案例導入後的結果 在每個確認測試案例被導入後,會存在兩種情況之一:
功能或效能特徵遵照規格且被接受 發現規格誤差,並產生一份缺點的列表。 此階段專案中所發現的誤差或錯誤很少可以在所排定遞交的時程前被改正。 它經常必須要與顧客協商,以建立解決錯誤的方法。

90 組態檢視 確認程序的一個重要元素是組態檢視(configuration review)。檢視的意圖是要確保所有軟體組態的元素已經被適當地發展、記載和具有支撐軟體生命週期支援階段所必要的細節。組態檢視有時稱為稽核(audit)。

91 13.5.3 Alpha與Beta測試 對一位軟體開發者實際上是不可能預知顧客將如何實際地使用一支程式。 使用的指令可能會被誤解;
可能習慣性地使用奇怪的資料組合; 對測試者似乎很明確的輸出,對現場的使用者可能是難以理解的。

92 驗收測試 當為顧客建造客製軟體時,一系列的驗收測試(acceptance tests)會被導入以讓顧客可以確認所有的需求。
由終端使用者所主導而非軟體工程師,此驗收測試範圍可以從非正式的「測試驅動(test drive)」到有計畫與有系統地執行一系列的測試。 驗收測試可能被導入超過數個星期或數月之久,因此可以揭發出可能降低系統的累積錯誤。

93 Alpha與Beta測試 如果軟體被展發成為一個讓許多顧客所使用的產品,但要對每一個人進行正式的驗收測試是不務實的。
軟體在很自然的設定下,開發者仔細檢查典型的使用者並記錄其錯誤與使用問題。 alpha測試在一個受到控制的環境中被導入。 Beta測試在終端使用者的地方被導入。 不像alpha測試,開發者通常是不在的。 beta測試是一個軟體「活的」應用,它在不受開發者所控制的環境中。 終端使用者記錄在beta測試期間遇到的所有問題(真正的或想像的),並向開發者定期報告。 在beta測試期間問題報告的結果,將令軟體工程師進行修改,然後準備將軟體產品對整個顧客市場發行。

94 13.6 系統測試 軟體只是一個很大的、以電腦為基礎系統中的一個元素。
軟體與其他的系統元素(例如,硬體、人、資訊)一起併入,且導入一系列的系統整合與確認測試。 這些測試落在軟體流程的範圍外,且不是由軟體工程師獨自所主導。 在軟體設計與測試期間所採取的步驟,可以大幅地改進在大系統中軟體成功整合的機率。 「如同死亡與稅金一樣,測試既是不愉快的,也是不可避免的。」 Ed Yourdon

95 潛在的介接問題 一個傳統系統的測試問題是「千夫所指(finger-pointing)」。 軟體工程師應該預先考慮潛在的介接問題,和:
這發生在當某個錯誤被揭發時,每位系統元素的開發者都為此問題而責備其他的人。 軟體工程師應該預先考慮潛在的介接問題,和: 設計錯誤處理路徑以測試來自系統其他元素的資訊。 導入一系列的測試,模擬錯誤資料或在軟體介面的其他潛在的錯誤。 記錄測試的結果,如果千夫所指的情況確實發生時,可以使用做為「證據」。 參與系統測試的計畫與設計,以確保軟體充分地測試。

96 系統測試 系統測試(system testing)實際上是一系列不同的測試,其主要的目的是完整地操練這個以電腦為基礎的系統。
雖然每項測試都有一個不同的目的,所有的工作都是要驗證系統元素已經適當地整合,並實行所配置的功能。

97 13.6.1 恢復測試(Recovery Testing)
許多以電腦為基礎的系統必須要在預先指定的時間內從錯誤中恢復並重新處理。 某些案例中,系統必須是可容錯的(fault tolerant) 。 處理錯誤必須不能導致整體系統的功能終止。 在其他的案例中,系統的錯誤必須要在一段指定的時間之內改正,否則會發生嚴重的經濟損失。

98 恢復測試 恢復測試(recovery testing)是一種系統測試,它以各種方式迫使軟體失去作用,並驗證恢復能被適當地實施。
如果恢復是自動的(由系統本身實行),重新初始化、檢查點機制(checkpoint mechanisms)、資料恢復和重新啟動等會被評估其正確性。 如果恢復需要人為的干預,則平均修復時間(mean-time-to-repair, MTTR)被用來評估,以決定它是否在可接受的限度中。

99 安全測試 任何管理敏感性的資訊或導致對個人不正當損害(或益處)動作的電腦系統都是非法侵入的目標。滲透跨越範圍廣大的活動:電腦駭客為了娛樂而嘗試滲透系統;不高興的員工嘗試滲透做為報復;不誠實的個人為了自己不法的獲益而嘗試滲透。

100 安全測試 安全測試(security testing)驗證建造於一個系統內的保護機制事實上是可以保護而不被滲透的。 引用Beizer的敘述:
「當然,系統的安全必須被測試,使得對於正面攻擊是無懈可擊的-但也必須要測試來自側面或後面的攻擊。」

101 進行系統滲透 在安全測試期間,測試者扮演想要滲透系統的角色。可以進行任何滲透! 給予充足的時間與資源,良好的安全測試終將滲透到系統中。
測試者要嘗試經由外部的手段取得密碼。 可以用設計破壞任何防衛建構的客製化軟體攻擊系統。 可以使系統不知所措,因而拒絕對其他的服務。 可能故意引起系統的錯誤,希望能在恢復期間進行滲透。 可能經由瀏覽不安全的資料,希望發現進入系統的關鍵。 給予充足的時間與資源,良好的安全測試終將滲透到系統中。 系統設計者的角色是讓滲透的花費遠超過所將獲得資訊的價值。

102 13.6.3 壓力測試(Stress Testing) 壓力測試是設計來對付程式不正常的情況。 基本上,執行壓力測試的測試者要問:
「在它失敗前,我們可以加速(crank)到多高?」

103 壓力測試 壓力測試(stress testing)以要求不正常數量、頻率或容積(volume)資源的方法執行一個系統。例如:
當其每秒的平均中斷數為一個或二個時,特別的測試可被設計成每秒產生十個中斷。 輸入資料的速率可能增加十倍,以決定輸入的功能將如何反應。 執行需要最大記憶或其他資源的測試案例。 設計可能會引起記憶體管理問題的測試案例。 產生可能引起磁碟駐留(disk-resident)資料過度搜尋(excessive hunting)的測試案例。 基本上,測試者嘗試使程式不知所措。

104 敏感度測試技術 壓力測試的變化是一種稱為敏感度測試(sensitivity testing)的技術。
在某些情形(最普遍出現在數學的演算法中),包含在一個程式有效資料界限中的一個非常小的資料範圍,它可能導致極端的行為和甚至不正確的處理,或很大的效能衰退。 敏感度測試嘗試揭發有效輸入類型中可能造成不穩定或不正常處理的資料組合。

105 13.6.4 效能測試 對於即時與嵌入式系統,提供所需要的功能,但是不能符合效能需求的軟體是無法被接受的。
效能測試(performance testing)是設計在整合的系統環境中測試軟體執行時期(run-time)的效能。 效能測試發生在測試流程中所有各方面的步驟。 甚至在單元層級的測試導入時,個別模組的效能可能會被評估。 要到所有的系統元素都完全整合後,系統的真實效能才能確定。

106 量測儀器的使用 效能測試時常與壓力測試結合,並且經常需要硬體與軟體的測試儀器。
時常需要以嚴格的方式量測資源的利用(例如,處理器週期)。 外部的測試儀器可以監控執行的間歇(intervals)、在它們發生時記錄事件(例如中斷)和定期對機械的狀態進行取樣。 藉由使用儀器量測系統,測試者可以揭發出導致衰退與系統可能的失敗情形。

107 13.7 除錯的藝術 軟體測試是一種可以系統化地計畫與明確指定的動作。 除錯(debugging)是成功測試所產生的結果。
測試案例設計可以導入、可以定義策略和可依規定的期望評估其結果。 除錯(debugging)是成功測試所產生的結果。 當某個測試案例揭發出一個錯誤時,除錯是造成錯誤移除結果的動作。 除錯可以且應該是一項有條理的流程,但它仍然非常像是一項藝術。

108 除錯的藝術 一位評估測試結果的軟體工程師時常面臨著軟體問題「具有症狀」的指示。
錯誤的外部表現和錯誤的內部起因可能對另一個而言是沒有明顯關係的。 缺乏理解連結症狀到起因的心智流程就是除錯。 「一旦我們開始編寫程式,我們驚訝的發現它不是那麼容易像我們想的一樣可以得到正確的程式。除錯必須被發覺。我可以記得我所瞭解最確切的例子是那時我生活中的一大部分被花費在我自己的程式中找尋錯誤。」 Maurice Wilkes, discovers debugging, 1949

109 13.7.1 除錯流程 除錯不是測試,但總是產生做為測試的結果。
13.7.1 除錯流程 除錯不是測試,但總是產生做為測試的結果。 參考圖13.7,除錯流程由執行測試案例開始,其結果會被評估,且會遇到預期與實際效能之間缺乏對應的情況。 在許多情形中,未對應到的資料是底層起因未被隱藏所產生的症狀。 除錯嘗試使症狀與起因相匹配,因此導致錯誤的改正。

110 圖13.7 除錯流程

111 除錯出現的結果 除錯將會出現兩種結果之一:
起因將被發現與改正 起因不會被發現。 在後者的情形中,實行除錯的人可能會懷疑起因,並設計一個或多個的測試案例以協助確認那個嫌疑,並且以反覆的形式進行錯誤的更正。

112 臭蟲的特性 為什麼除錯如此困難? 一些臭蟲的特性可以提供一些線索:
在所有的可能性中,人類心理學(請參考下一部分)還有比軟體科技的答案更多要做的。 一些臭蟲的特性可以提供一些線索: 症狀與起因的距離可能是很遙遠的。 即症狀可能在程式中的一部分出現,而起因實際上可能位在遠於被移除的地方。 高度耦合的元件(第11章)會使這種情形惡化。 當另一個錯誤被改正時,症狀可能會消失(暫時地)。 症狀實際上可能是由非錯誤所造成(例如,四捨五入的不精確)。

113 臭蟲的特性 症狀可能是由人類的錯誤所引起,而不容易被追蹤。 症狀可能是時序(timing)問題的結果,並非處理的問題。
正確地重新產生輸入的情況可能是很困難的(例如,即時應用系統的輸入次序是不確定的)。 症狀可能是間歇性的。 這種硬體與軟體耦合而糾纏不清的情形在嵌入式系統中特別普遍的存在。 症狀可能是由於分散執行於不同處理器的許多任務所造成的。

114 除錯的壓力 在除錯期間,我們所遇到的錯誤從略微惱人的(例如不正確的輸出格式)到災難性的(例如,系統當機造成嚴重的經濟或實質的損壞)錯誤。
由於錯誤增加的結果,尋找起因的壓力也增加。 經常地,壓力迫使軟體開發者修正一個錯誤的同時又引入另外二個錯誤。 「每個人都知道除錯比從頭開始撰寫程式困難二倍。所以如果你是聰明人,在你撰寫它時,你究竟將如何除錯?」 Brian Kernighan

115 13.7.2 心理上的考量 有一些證據顯示除錯的本領高超是與生俱來的特性。 評論人類除錯的面向,Shneiderman說道:
某些人擅長,而其他則不是。 雖然在除錯上的實驗證據公開了許多解釋,但已經有報告指出具有相同教育與經驗的程式設計師,在除錯能力上也有很大的差異。 評論人類除錯的面向,Shneiderman說道: 除錯是程式設計中最令人受挫的一部分。 它具有問題解決或智力戲弄者(teasers)的要素,連接到你所犯下錯誤的討厭報償。 增強了焦慮和不情願去接受錯誤會增加工作困難度的可能性。 幸運地,當臭蟲最後終於…改正時,就有令人安心的聲息並降低緊張。 雖然除錯可能難以「學習」,但對問題的許多方式都可被建議。

116 13.7.3 除錯策略 不管所選擇的方式,除錯有一個優先的目標:
13.7.3 除錯策略 不管所選擇的方式,除錯有一個優先的目標: 發現並改正軟體錯誤的起因。 此目標是藉由系統化評估的組合、直覺和運氣來實現。Bradley描述除錯的方法如下: 除錯是已經發展超過2,500年科學方法的直接應用。 除錯的基礎是藉著二分法(binary partitioning),經過進行假設預測所將被檢查的新值以確定問題的來源(起因)。

117 除錯策略的範例 一個簡單但非軟體的例子: 我的家中有一盞燈不亮了。 如果家中其他的也都不動,起因一定是在主要的線路斷路器或外面。
我會四處看看鄰近的地區是否也是暗的。 我將懷疑的燈插入到可供電的插座,或將可動作的電器插入懷疑的線路中。 如此交互地做假設與測試。

118 建議的除錯策略 三個建議的除錯策略: 這些策略的每一個都可以用手動導入,但是現代的除錯工具可使流程更為有效。
暴力(brute force) 回溯(backtracking) 起因消除(cause elimination) 這些策略的每一個都可以用手動導入,但是現代的除錯工具可使流程更為有效。 「修理損壞程式的第一個步驟是讓它可以重複地失誤(在最可能簡單的例子上)。」 T. Duff

119 除錯的戰術-暴力 除錯的暴力(brute force)類型可能最常用,但卻是隔離軟體錯誤起因最沒有效率的方法。
當所有其他的方法都失效時,我們應用暴力除錯。 使用「讓電腦發現錯誤」的哲學,採取記憶傾卸(memory dump)、召喚即時追蹤和讓程式與輸出敘述一起載入。 我們希望在資訊產生困境的地方,我們將發現一個可以引導我們到達錯誤起因的線索。 雖然所產生的大量資訊最後可能導致成功,但它時常導致努力與時間的浪費。 想法首先必須要被耗盡!

120 除錯的戰術-回溯 回溯(backtracking)是相當普遍的除錯方式,它可成功地使用於小的程式中。
由發現症狀的地方開始,往後(手動地)追查原始碼,直到發現起因為止。 不幸地,原始碼的數量不斷地增加,潛在的回溯路徑可能變得多到無法管理。

121 除錯的戰術-起因消除 藉由歸納(induction)或演繹(deduction)和引入二分法(binary partitioning)的概念而顯露出。 與錯誤出現相關的資料被組織以隔離潛在的起因。 策劃出「起因假說(cause hypothesis)」,並使用上述所提及的資料來證明或反駁假說。 發展出所有可能起因的列表,且導入測試以消除每一個。 如果開始的測試指出特定起因的假說顯現出有符合的希望,則在嘗試隔離臭蟲的行動中,資料會被改進。

122 人的因素 任何除錯方式與工具的討論若沒提到一個有力的夥伴-其他的人,則是不完整的! 在挫折幾小時之後,確實會想知道另一個新的觀點。
給除錯的最後一句箴言可能是: 當其他所有的都失敗時,找幫手!

123 13.7.4 改正錯誤 一旦發現一個臭蟲,它必須要被改正。
13.7.4 改正錯誤 一旦發現一個臭蟲,它必須要被改正。 臭蟲的改正可能引進其他的錯誤,損害因此會比好處多。 Van Vleck提出三個在進行移除臭蟲起因的「更正」前,每位軟體工程師應該要問的問題: 臭蟲的起因會在程式的其他部分重新產生嗎? 在許多情形中,程式的錯誤是由邏輯的錯誤模式所造成,它也可能在其他地方重新產生。 明顯地考慮邏輯模式可導致其他錯誤結果的發現。

124 改正錯誤 由於我所修定而可能引起的「下一隻臭蟲」是什麼? 開始的時候我們可以做什麼以避免臭蟲嗎?
在改正之前,原始碼(或更好的是設計)應該評估已確定的邏輯與資料結構的耦合。 如果在程式高度耦合的部分進行改正,當進行任何改變時,必須要特別的謹慎。 開始的時候我們可以做什麼以避免臭蟲嗎? 此問題的第一個步驟是朝向建立一個統計的軟體品質保證方式。 如果我們改正流程與產品,臭蟲將從現有的程式中移除,也可能從未來的所有程式中移除。


Download ppt "軟體工程第六版 第十三章 測試策略."

Similar presentations


Ads by Google