# 測試案例設計入門 在開始瞭解如何開始設計測試案例之前,首先你該知道測試的本質是在於檢驗事物的正確性。它是一種風險管理的工具,用來協助團隊理解現況與做出決定。 ![Risk Management](http://onefloorupdenver.com/assets/images/uploads/blog_photos/tcq_tri.png) * 速度與成本: 品質不佳 * 成本與品質: 時間過長 * 品質與時間: 成本過高 在實務上測試工程師經常面臨的難題是如何在三者間取得平衡,充分的溝通與團隊合作可建立團隊共識,對於品質標準有一致性的認知。 而隨著產品商業環境的不同,品質標準與策略有可能截然不同。在金融與醫療產業,些許的差錯就可能造成金錢或是生命安全的損失,因此對於品質往往有非常高的要求與標準。 KKBOX 提供的是音樂串流服務,屬於娛樂性質的商業環境,快速的反應市場變化來創造話題與潮流。在這樣的生態下,快速發佈會比品質更為重要。 ## 你會如何測試這部電話 ? ![電話](http://iriefm.net/wp-content/uploads/telephone.jpg) 常見的幾種回答: 1. 測試能不能撥打電話 2. 測試能不能接收電話 3. 把所有按鈕按過一遍,確保每個按鈕都能正常做用 在開始進行測試之前,你應該對基本商業需求有所認知,了解使用者會如何使用這些產品。有了這些認知設計出來的測試案例會具有較高的價值。而伴隨著不同的測試目的,測試的方法與重點會截然不同。 ## 認識測試案例 測試的本質是在於檢驗事物的正確性,然而單單找到問題還不夠。更重要的是問題是否可以被複製,可以被複製的問題才有機會被解決,透過系統思考與測試方法為測試本身建立測試案例,讓測試具有可預期性與重複性是測試工程師的核心價值。 所謂的**測試案例**是指描述測試內容的文件,其基本要素包含了下列項目: - **編號**: 非重複性的編號,用於規劃與管理測試案例 - **標題**: 描述測試的目的,通常會包含情境與預期結果 - **前置條件**: 測試的前置狀態 - **測試步驟**: 測試的步驟 - **預期結果**: 如何判斷測試成功或失敗 - **優先權**: 測試的優先順序,當時間有限時它可以幫助你決定如何做出的取捨 <table> <tr> <th>編號</th> <th>標題</th> <th>前置條件</th> <th>測試步驟</th> <th>預期結果</th> <th>優先權</th> </tr> <tr> <td>TC_001</td> <td>使用者可撥打內線電話與另一內線分機通話</td> <td>電話已連接線路</td> <td>輸入電話號碼 `666`</td> <td>1. 撥打內線電話至分機 `666`<br /> 2. 接通後可與對方通話</td> <td>高</td> </tr> </table> ### 測試與開發間的關係 在傳統的瀑布式開發模型裡測試往往安排在開發完成之後,此一方法最大的問題在於無法提供即時的回饋,進而造成重工與時程上的延遲。 ![Waterfall](https://changearc.files.wordpress.com/2013/03/riskywaterfall.png) **V-Model**: 瀑布式開發模型模型的延伸。此一模型裡揭露的開發與測試間的關係,其最早可被追溯至 1986 年為德國軍方所使用,不同於瀑布式模型,它強調的是在系統建置與發展的各種時期,都應該有其對應的測試來即時給予回饋。此一模型內的觀念也被運用在現代開發/測試模型裡。如測試驅動開發 (TDD),驗證測試驅動開發 (ATDD)或是測試金字塔 (TestPyramid ) 等。 ![V-Model](https://i0.wp.com/www.testnbug.com/wp-content/uploads/2014/12/v-model.png) V-Model 模型將測試分為 4 個層級: ### 1. 驗收測試 (Acceptance Testing): 驗收測試的目的在於驗證產品需求的正確性,這類型的測試會在專案初期進行設計,也因為此時通常沒有技術文件可供參考,它通常不會考量太多技術細節。 產品需求可能以各種形式出現: * 幾張圖: ![MockUp](http://jo-chang.com/wp-content/uploads/2016/10/PP_DetailedDesign_imgs4.jpg) * 一句話: 使用者可以透過撥打電話與另一方通話。 * Story: 當使用者撥打電話後,系統會連接使用者與另一方如此雙方便可以使用語音快速溝通。 難題在於一句話各自表述,俗話就是各自腦補,每個人對這樣的產品都有各自的解讀。且難以察覺彼此想法的不同,若能將這些產品需求實例化,可有效減少認知上的錯誤。 #### 實例化 - 當使用者輸入電話號碼 `666`,即可撥打內線電話至分機 666。 - 當使用者輸入電話號碼 `(02)2655-7557`,即可撥打國內電話至 KKBOX Taiwan。 - 當使用者輸入電話號碼 `948794`,無法進行撥號。 #### 測試案例 <table> <tr> <th>編號</th> <th>標題</th> <th>前置條件</th> <th>測試步驟</th> <th>預期結果</th> <th>優先權</th> </tr> <tr> <td>TC_001</td> <td>使用者可撥打內線電話與另一內線分機通話</td> <td>電話已連接線路</td> <td>輸入電話號碼 `666`</td> <td>1. 撥打內線電話至分機 `666`<br /> 2. 接通後可與對方通話</td> <td>高</td> </tr> <tr> <td>TC_002</td> <td>使用者可撥打國內電話與其他號碼通話</td> <td>電話已連接線路</td> <td>輸入電話號碼 `(02)2655-7557`</td> <td>1. 撥打國內電話號碼 `(02)2655-7557` <br /> 2. 接通後可與對方通話</td> <td>高</td> </tr> <tr> <td>TC_003</td> <td>系統會提示使用者撥打了無效的電話號碼</td> <td>電話已連接線路</td> <td>輸入電話號碼 `948794`</td> <td>系統回覆該號碼不存在</td> <td>中</td> </tr> </table> ### 2. 系統測試 (System Testing): 系統測試的目的是在於驗證應用程式的正確性,此一階段伴隨著明確的系統需求與技術規範,此時測試會將技術細節考量進行。在這個階段從基礎的功能性測試乃至相容性測試、多國語系等都會視專案需求而分階段進行。 為了驗證系統的正確性,測試工程師會盡可能的設計各式測試案例來減少系統的錯誤。剛進入測試領域的工程師很容易陷入窮舉的陷阱,而設計出低效率的測試案例。 以一個僅接受 `1 ~ 1000` 的可輸入欄位為例,你會需要設計幾個測試案例來測試它 ? #### 測試案例 <table> <tr> <th>編號</th> <th>輸入數字</th> <th>預期結果</th> <th>備註</th> </tr> <tr> <td>1.</td> <td>0</td> <td>失敗</td> <td>最小值 - 1</td> </tr> <tr> <td>2.</td> <td>1</td> <td>成功</td> <td>最小值</td> </tr> <tr> <td>3.</td> <td>2</td> <td>成功</td> <td>最小值 + 1</td> </tr> <tr> <td>4.</td> <td>666</td> <td>成功</td> <td>界於最小值與最大值間的數字</td> </tr> <tr> <td>5.</td> <td>999</td> <td>成功</td> <td>最大值 - 1</td> </tr> <tr> <td>6.</td> <td>1000</td> <td>成功</td> <td>最大值</td> </tr> <tr> <td>7.</td> <td>1001</td> <td>失敗</td> <td>最大值 + 1</td> </tr> </table> 此一方法為**邊界值分析**,是測試工程師不能不瞭解的技巧。進一步的分析,我們可以把這 7 個數字切分為 3 個區塊. ``` ..... -2 -1 0 1 2 ..666.. 999 1000 1001 1002 1003 ..... -------------|--------------------|-------------------- 不合法輸入 1 合法輸入 不合法輸入 2 ``` 同一區塊內,你該考量的是測試效益的問題,比方說: 2, 3, 4, 666, 997, 998, 999 這幾個數字在此一條件下其實等效的,測試這些數字除了增加測試時間外,實質上對於正確性來說沒有絲毫的幫助。 透過這個方法我們其實可以把先前的測試略做簡化,但仍不損測試的完整性。 <table> <tr> <th>編號</th> <th>輸入數字</th> <th>預期結果</th> <th>備註</th> </tr> <tr> <td>1.</td> <td>0</td> <td>失敗</td> <td>最小值 - 1</td> </tr> <tr> <td>2.</td> <td>1</td> <td>成功</td> <td>最小值</td> </tr> <tr> <td>3.</td> <td>666</td> <td>成功</td> <td>界於最小值與最大值間的數字</td> </tr> <tr> <td>4.</td> <td>1000</td> <td>成功</td> <td>最大值</td> </tr> <tr> <td>5.</td> <td>1001</td> <td>失敗</td> <td>最大值 + 1</td> </tr> </table> 此一方法為**等價類劃分法**,它經常搭配**邊界值分析**共同使用,透過這些方法可幫助你刪除那些無謂的測試,並增進整體效率。 ### 3. 整合測試 (Integration Testing): 整合測試概念上來說其實是相當模糊與籠統的,它可以是跨越兩個 Function Call 以上的測試,也可以是跨越二十個 Class 以上的測試。如果我們將單一函式視為最小單位的積木,整合測試即是確保由數個積木組合而成的元件符合我們的設計。 而就如同你想像的,數個元件的結合就構成了一套系統。 ### 4. 單元測試 (Unit Testing) 所謂單元測試就是以程式中最小的邏輯單元為對象,撰寫測試程式,來驗證邏輯正確與否。一般來說,程式中最小的邏輯單元就是函式,或是方法(method)。 而通常單元測試會由開發人員負責,原因是在於單元測試經常伴隨著重構 (Refactoring) 進行。 ### 測試審查 (Test Review) 在設計測試案例的過程中,取得團隊的回饋是相當重要的。測試審查應發生在當完成階段性的測試設計工作後,透過邀請產品與開發人員來共同審查測試的涵蓋率。確保重要的使用者情境與要素有被涵蓋。 而使用心智圖來呈現測試涵蓋範疇是目前比較常見的做法。 ![Apple Watch App 離線播放](https://i.imgur.com/8lihL9V.png) ## 如何規劃與執行測試案例 在測試案例設計完成後,測試工程師必須思考如何有效率的規劃與執行這些測試案例。在 Android App 的生態裡碎片化是一個普遍的問題,你會如何確保 App 能在不同的裝置上運作 ? ![Android Model](https://i.kinja-img.com/gawker-media/image/upload/s--PWFVWZ4z--/c_scale,f_auto,fl_progressive,q_80,w_800/yk5udb2szuxo0xp0yiom.png) ### 選擇測試組合 經由分析、歸納與分類我們可以把龐大且複雜的問題,分解成多個小問題。把問題縮小了,才有機會解決。 而 [Android Dashboards](https://developer.android.com/about/dashboards/index.html) 即是官方針對此一議題釋出的數據,透過 3 種要素來簡化其複雜度: #### 1. Android 版本: 12 <table> <caption>Android 版本</caption> <tr> <th>版本</th> <th>API</th> <th>比例</th> </tr> <tr> <td>2.3.3 - 2.3.7</td> <td>10</td> <td>0.6%</td> </tr> <tr> <td>4.0.3 - 4.0.4</td> <td>15</td> <td>0.6%</td> </tr> <tr> <td>4.1.x</td> <td>16</td> <td>2.3%</td> </tr> <tr> <td>4.2.x</td> <td>17</td> <td>3.3%</td> </tr> <tr> <td>4.3</td> <td>18</td> <td>1.0%</td> </tr> <tr> <td>4.4</td> <td>19</td> <td>14.5%</td> </tr> <tr> <td>5.0</td> <td>21</td> <td>6.7%</td> </tr> <tr> <td>5.1</td> <td>22</td> <td>21.0%</td> </tr> <tr> <td>6.0</td> <td>23</td> <td>32.0%</td> </tr> <tr> <td>7.0</td> <td>24</td> <td>15.8%</td> </tr> <tr> <td>7.1</td> <td>25</td> <td>2.0%</td> </tr> <tr> <td>8.0</td> <td>26</td> <td>0.2%</td> </tr> </table> #### 2. 螢幕解析度: 15 <table> <caption>螢幕解析度</caption> <tr> <td></td> <td>ldpi</td> <td>mdpi</td> <td>tvdpi</td> <td>hdpi</td> <td>xhdpi</td> <td>xxhdpi</td> </tr> <tr> <td>Small</td> <td>0.7%</td> <td></td> <td></td> <td></td> <td></td> <td></td> </tr> <tr> <td>Normal</td> <td></td> <td>1.5%</td> <td>0.2%</td> <td>30.5%</td> <td>36.7%</td> <td>21.3%</td> </tr> <tr> <td>Large</td> <td>0.1%</td> <td>2.9%</td> <td>1.6%</td> <td>0.5%</td> <td>0.9%</td> <td>0.1%</td> </tr> <tr> <td>Xlarge</td> <td></td> <td>2.0%</td> <td></td> <td>0.5%</td> <td>0.5%</td> <td></td> </tr> </table> ### 3. OpenGL Version: 3 <table> <caption>OpenGL 版本</caption> <tr> <th>版本</th> <th>比例</th> </tr> <tr> <td>2.0</td> <td>36.9%</td> </tr> <tr> <td>3.0</td> <td>45.6%</td> </tr> <tr> <td>3.1</td> <td>17.5%</td> </tr> </table> 現假設有 15 項測試案例必須完整考慮這 3 種要素的所有可能,那 15 項測試案例會變成 8100 項測試,測試總數會隨著必須納入考量的因數而呈現指數級的成長。 ![完整測試組合](https://i.imgur.com/gUxQelH.png) 在多數的情況裡,測試工程師不會有足夠的時間或資源來完成所有測試。因此溝通與簡化測試組合就非常重要,透過溝通與協同合作,你的團隊可以幫助你理解哪些測試組合可以被捨去,哪些又該被考量進來。 此外,這裡也有一些基本的準則與方法可以幫助你與團隊做出決定。 1. 最舊的版本 2. 最新的版本 3. 最小的螢幕 4. 最大的螢幕 5. 最多人使用 以 KKBOX 為例,基於這些準則與商業環境考量,我們略作簡化如下: #### 1. Android 版本: 12 -> 6 <table> <caption>Android 版本</caption> <tr> <th>版本</th> <th>API</th> <th>比重</th> <th>KKBOX</th> <th>備註</th> </tr> <tr> <td>2.3.3 - 2.3.7</td> <td>10</td> <td>0.6%</td> <td></td> <td></td> </tr> <tr> <td>4.0.3 - 4.0.4</td> <td>15</td> <td>0.6%</td> <td>V</td> <td>最低支援版本</td> </tr> <tr> <td>4.1.x</td> <td>16</td> <td>2.3%</td> <td></td> <td></td> </tr> <tr> <td>4.2.x</td> <td>17</td> <td>3.3%</td> <td></td> <td></td> </tr> <tr> <td>4.3</td> <td>18</td> <td>1.0%</td> <td></td> <td></td> </tr> <tr> <td>4.4</td> <td>19</td> <td>14.5%</td> <td>V</td> <td>最多人使用的 4.X 系列</td> </tr> <tr> <td>5.0</td> <td>21</td> <td>6.7%</td> <td></td> <td></td> </tr> <tr> <td>5.1</td> <td>22</td> <td>21.0%</td> <td>V</td> <td>最多人使用的 5.X 系列</td> </tr> <tr> <td>6.0</td> <td>23</td> <td>32.0%</td> <td>V</td> <td>最多人使用的 6.X 系列</td> </tr> <tr> <td>7.0</td> <td>24</td> <td>15.8%</td> <td>V</td> <td>最多人使用的 7.X 系列</td> </tr> <tr> <td>7.1</td> <td>25</td> <td>2.0%</td> <td></td> <td></td> </tr> <tr> <td>8.0</td> <td>26</td> <td>0.2%</td> <td>V</td> <td>最新的版本</td> </tr> </table> #### 2. 螢幕解析度: 15 -> 5 <table> <caption>螢幕解析度</caption> <tr> <td></td> <td>ldpi</td> <td>mdpi</td> <td>tvdpi</td> <td>hdpi</td> <td>xhdpi</td> <td>xxhdpi</td> </tr> <tr> <td>Small</td> <td>**0.7%**</td> <td></td> <td></td> <td></td> <td></td> <td></td> </tr> <tr> <td>Normal</td> <td></td> <td>1.5%</td> <td>0.2%</td> <td>**30.5%**</td> <td>**36.7%**</td> <td>**21.3%**</td> </tr> <tr> <td>Large</td> <td>0.1%</td> <td>2.9%</td> <td>1.6%</td> <td>0.5%</td> <td>0.9%</td> <td>0.1%</td> </tr> <tr> <td>Xlarge</td> <td></td> <td>2.0%</td> <td></td> <td>0.5%</td> <td>**0.5%**</td> <td></td> </tr> </table> ### KKBOX App 未特別用 OpenGL 無需納入考量 在一樣的 15 項測試案例下,測試總數從 8100 下降 450 但仍能保有足夠的信心。 ![精簡測試組合](https://i.imgur.com/XA3f5ft.png) ### Pairwise Independent Combinatorial Testing tool 在先前的討論裡,我們提到了若要完整考慮 Android Dashabords 裡的 3 種要素,總計會有 12 x 15 x 3 x 15 = 8100 項測試。 這種做法雖然全面,但非常不實際,除了減少低風險的要素外,還有一種方法可以有效的減少測試組合,它稱作為 [Pairwise Testing](http://www.pairwise.org/) Pairwise 是透過找出兩要素間的最大關聯取來代窮舉方法,在這個模型底下測試組合可以被大幅縮小但仍保有有效性,要素越多 Pairwise Testing 越能發揮效用。 ![完整測試組合](https://i-msdn.sec.s-msft.com/dynimg/IC91126.gif) ### 安排測試順序 有了測試案例與測試組合後, 便可以開始安排測試進行的順序。測試階段會隨著軟體開發模式與發佈頻率的差異而有所不同,但普遍來說, 測試順序可概略的分成 3 個階段: 1. 新功能測試 2. 回歸測試 3. 驗收測試 ![完整測試組合](https://i.imgur.com/d3OO8vu.png) #### 新功能測試 在這個階段,測試的重點在於確保新功能在各種面向是否正確。在 KKBOX 此時測試的面向包含了: 1. 功能測試 2. 相容性測試 3. 多國語系測試 #### 回歸測試 回歸測試的目的在於確保過去已開發的功能,不會受到這次新功能的增加而造成副作用。在這個階段我們會進行: 1. 問題的驗證 2. 探索測試 3. 既有功能的回歸測試 有別於一般的測試講的是`可重複性`與`預測性`,探索測試的精神在於不要總是測試一樣的路徑。當執行探索測試時,我們會設定測試時間為 120 分鐘,並賦予一或多個測試主題,比方說: 網路慢的時候。測試人員會一邊思考網路速度不佳的情境,一邊執行測試。它仰賴的是測試人員對於產品與技術的熟悉程度,透過這種非既定的測試能發現一些出乎意料的問題,並且能持續改進測試案例的涵蓋範疇。 #### 驗收測試 驗收測試其實也是一種回歸測試,只是它的範疇更小一點。規劃這樣的測試階段是因為通常回歸測試的期間,測試的版本會持續地推進。比方說開始測試時是 1.1.0 到了測試完成時已經進入到 1.1.3。這表示回歸測試期間跨越了 4 個版本,而每進版一次就增加了一些風險,因為這些變動也很有可能會造成退化問題 (Side-Effect)。 為了降低這些風險,在最後階段每一個版本我們都會進行所謂的驗收測試。這種快速精簡的驗收測試可以減少後續緊急修正的機率。在某些組織裡會採用僅執行驗收測試的策略,而沒有完整的回歸測試,這一切的考量最終都是回到時間、成本與品質上的取捨。 ## 持續學習 由於台灣的產業結構,目前投身軟體產業的人相較於硬體仍是少數,而軟體測試工程師則是更是少之又少。Marc Andreessen 於 2011 年發表了一篇文章: [Why Software Is Eating The World ](https://www.wsj.com/articles/SB10001424053111903480904576512250915629460),文章裡說的是軟體正在改變世界,而過去 6 年來此一趨勢演變的更加顯著,然而台灣的測試思維仍是過於硬體導向。透過這篇基礎文章,希望能發揮啟蒙的功效,並讓軟體測試的議題更加被重視與注意。 最後推薦一些持續學習的資源,也歡迎各方意見與想法上的交流。 ### 測試社群 * Test Corner: https://www.facebook.com/groups/test.corner/ ### 推薦書籍 ##### 軟體測試之道: 微軟測試團隊的成功經驗、方法與技術 ![軟體測試之道: 微軟測試團隊的成功經驗、方法與技術](https://kingstonebk.azureedge.net/book/images/product/20147/2014713215390/2014713215390b.jpg) ##### Google軟體測試之道:進行Google級的軟體測試 ![Google軟體測試之道:進行Google級的軟體測試](http://im1.book.com.tw/image/getImage?i=http://www.books.com.tw/img/001/062/35/0010623556.jpg&v=52ce7b1a&w=280) ##### Specification by Example 中文版:團隊如何交付正確的軟體 ![Specification by Example 中文版:團隊如何交付正確的軟體](http://im2.book.com.tw/image/getImage?i=http://www.books.com.tw/img/001/064/42/0010644283.jpg&v=53ce4b41&w=280) ##### Lessons Learned in Software Testing: A Context-Driven Approach ![Lessons Learned in Software Testing: A Context-Driven Approach ](https://images-na.ssl-images-amazon.com/images/I/51x4vnpXN3L._SX404_BO1,204,203,200_.jpg)