概念: 測試構想清單
測試構想清單是一份依重要性遞減排列的測試構想,與用來建立可行測試的特定測試策略有關。
關係
主要說明

簡介

設計測試中使用的資訊有許多來源:設計模型、分類器介面、狀態圖及程式碼本身。此來源文件資訊有時必須轉換成可執行的測試:

  • 對測試中的軟體所提供的特定輸入
  • 特定的軟硬體配置
  • 起始設定為已知狀態
  • 預期特定的結果

也可以直接從來源文件資訊進入可執行的測試,但通常最好加入一個中間步驟。在此步驟中,測試構想會寫在測試構想清單上,再利用此清單來建立可執行的測試。

什麼是測試構想?

測試構想(有時稱為測試需求)是對可執行的測試所做的簡短描述。舉一個簡單的例子,假設有一個計算平方根的函數,我們提出一些測試構想:

  • 給定一個完全小於零的數字做為輸入
  • 給定零做為輸入
  • 測試一個完全平方的數字,例如 4 或 16(剛好是 2 或 4 的結果嗎?)

依據完全相同的輸入描述和預期結果,以上每一個構想可立即轉換成可執行的測試。

採用這種普通的中間格式有兩項優點:

  • 測試構想比完整測試更易於審查和理解 - 很容易瞭解背後的推論
  • 測試構想支援更強的測試,請參閱使用清單進行測試設計標題稍後的說明

平方根範例完全只描述輸入,但測試構想可描述一個可執行測試的任何元素。例如,「列印到 LaserJet IIIp」描述測試採用的測試環境的一個層面,就像「在資料庫已滿的情況下測試」一樣,不過,後面的這些測試構想本身就相當不完整:究竟將什麼列印到印表機? 對已滿的資料庫做什麼?不過,的確可以保證不會遺忘重要的構想;測試設計稍後會更詳細描述這些構想。

測試構想通常以錯誤模型為基礎;懷疑軟體中可能有哪些缺陷及如何以最佳方式發現這些缺陷。例如,以界限為例。可確定推斷平方根函數可能實作如下:

double sqrt(double x) {
    if (x < 0)
      // 信號錯誤
    ...

< 也可能誤打為 <=。這是常見的錯誤,值得檢查。如果 X 的值為 2,則無法偵測到錯誤,因為不正確的表示式 (x<=0) 和正確的表示式 (x<0) 會採取相同的 if 陳述式分支。同樣地,X 的值為 -5 也找不出錯誤。唯一的辦法是給定 X 的值為 0,可以證實第二個測試構想。

在此例子中,錯誤模型很明確。在其他情況下就不明顯。例如,每當程式操作鏈結結構時,最好以循環鏈結結構來做測試。有許多缺陷可能產生無法處理的循環結構。基於測試的目的,不一定要舉出所有缺陷,只要知道一些值得測試的缺陷即可。

下列鏈結提供一些在不同的錯誤模型類型中獲得測試構想的相關資訊。前兩個是明確的錯誤模型;最後一個採用隱含模型。

這些錯誤模型適用於許多不同的工作成果。例如,第一個模型說明如何處理 Boolean 表示式。這種表示式出現在程式碼、警戒條件、狀態圖和序列圖,以及方法行為的自然語言描述中(例如,在已發佈的 API 中可以找到)。

特定工作成果最好也要有一些準則。請參閱準則:狀態圖和流程圖的測試構想

特定的「測試構想清單」可能包含許多錯誤模型的測試構想,且這些錯誤模型可能衍生自多個工作成果。

使用清單進行測試設計

假設您要為一個方法設計測試,此方法可在順序集合中搜尋字串。搜尋時可能區分大小寫或不區分大小寫,最後會傳回第一個相符項目的索引,如果找不到相符項目,則傳回 -1。

int Collection.find(String string,
            Boolean ignoreCase);

此方法的一些測試構想如下:

  1. 在第一個位置發現相符項目
  2. 在最後一個位置發現相符項目
  3. 找不到相符項目
  4. 在集合中發現兩個以上的相符項目
  5. 不區分大小寫;發現相符項目,但如果區分大小寫,則不相符
  6. 區分大小寫;發現完全相符的項目
  7. 區分大小寫;已跳過一個字串,但如果不區分大小寫,此字串就相符

實作這七種測試很簡單,每一個測試構想測試一次即可。然而,不同的測試構想可合併成單一測試。例如,下列測試可滿足測試構想 2、6 及 7:

設定:集合起始設定為 ["dawn", "Dawn"]
呼叫:collection.find("Dawn", false)
預期結果:回覆值為 1(如果未跳過 "dawn",則傳回 0)

測試構想愈不特殊,愈容易合併。

有可能以三個測試來滿足所有測試構想。為何以三個測試滿足七個測試構想會比七個分開的測試更理想?

  • 當您建立大量簡單的測試時,通常會複製測試 N 再加以修改來滿足新的測試構想,以建立測試 N+1。結果,尤其在很複雜的軟體中,測試 N+1 推演程式的情形可能幾乎完全同於測試 N。在程式碼中通過的路徑幾乎完全相同。

    測試數量太少(每一項都滿足七個測試構想)並不適用「複製並調整」方法。各項測試彼此有些許差異,有不同的方式推演程式碼且採取不同的路徑。

    這樣為什麼更好?只要「測試構想清單」很完整,對程式的每一個缺陷都有測試構想,則您如何撰寫測試並不重要。但此清單總是會遺漏一些可尋找錯誤的測試構想。讓每一項測試各負責一件很不相同的事 (加上看似沒必要的變化),可以提高其中一項測試幸運地發現錯誤的機會。事實上,在小而複雜的測試中,測試更有可能滿足您不知道自己所需的測試構想。

  • 在建立更複雜的測試時,往往會浮現新的測試構想。這在簡單的測試中較少發生,因為您正在做的很多事幾乎就等於上一個測試的翻版,也就不易發揮您的靈感。

然而,不要建立複雜的測試有其理由。

  • 如果每一項測試只滿足單一測試構想,且構想 2 的測試失敗,則馬上知道最可能的原因:程式無法處理最後一個位置發現的相符項目。如果測試滿足構想 2、6 及 7,則很難釐清失敗的原因。

  • 複雜的測試比較難理解和維護。測試的意圖較不明確。

  • 複雜的測試比較難建立。建構一個測試來同時滿足五個測試構想所需的時間,通常大於建構五個測試來各自滿足一個構想所需的時間。再者,很容易誤解 - 誤以為五個構想全部滿足,事實上只滿足四個。

實際上,您必須在複雜與簡化之間追求一個合理的平衡點。例如,您提供給軟體的前幾個測試(通常是輕度測試)應該簡單、易於理解和維護,且目標是擷取最明顯的問題。後續的測試才應該愈來愈複雜,但不能複雜到不可收拾的局面。

完成一組測試之後,最好再根據概念:開發人員測試中討論的一般測試設計錯誤,仔細檢查一次。

測試之前使用測試構想

「測試構想清單」很適合用來審查和檢驗設計工作成果。 例如,請看這部分的設計模型,其中顯示 Department 和 Employee 類別之間的關聯。

設計模型範例圖

圖 1:Department 與 Employee 類別之間的關聯

以這種模型來建立測試構想時,習慣上會要求您考慮一個部門有許多員工的情況。經由檢查設計並詢問「此時,如果部門有許多員工,會是如何?」,您可能會發現設計或分析錯誤。例如,您可能瞭解一次只有一位員工可以在部門之間轉調。如果公司經常全面改組,許多員工需要調任,則可能會有問題。

這種缺陷(忽略一種可能性的情況)稱為疏失缺陷。就像缺陷本身一樣,您可能會省略測試,無法從您的測試工作中發現這些缺陷。例如,請參閱 [GLA81][OST84][BAS87][MAR00] 及其他研究,這些資料顯示在部署中發生疏失缺陷的情形。

概念:測試優先設計進一步討論測試在設計活動中扮演的角色。

測試構想與追蹤性

追蹤性是有關權衡的問題。是否值得花費成本來維護? 在 作業:定義評估和追蹤性需求期間必須考慮這種問題。

在值得掌握追蹤性時,通常會從測試回溯至最初策動測試的工作成果。例如,您可能掌握 API 和測試之間的追蹤性。如果 API 改變,您知道要變更哪些測試。 如果程式碼(實作 API 的程式碼)改變,您知道要執行哪些測試。 如果有一項測試讓您感到困惑,您可以尋找原本打算測試的 API。

「測試構想清單」可提高追蹤性。您可以從測試追蹤至預定滿足的測試構想,再從測試構想追蹤至原來的工作成果。