Sunday, April 10, 2011

軟體測試:Unit Test 隨便談,從動機到工作流程改善

在軟體測試的領域裡,最能夠吸引開發者的測試系統大概就是 Unit Test。這難以假手於他人的 Best Practice,莫不提起開發者對於 Unit Test 既予高度的期待。大部分的討論主題都是在教你如何寫出容易維護的 Unit Test,或是提高 Testability 的程式設計技巧。但我認為更重要的是要討論 Unit Test 的動機,進而了解它對於專案開發效益,到底可以帶給開發團隊什麼樣的好處。

上圖說明了我們對於軟體開發過程的假設。在任何階段產生的臭蟲,如果不能及時被抓出來,維修的成本提昇的速度會隨著它潛伏的時間快速成長。舉個例子,Toyota 的煞車延遲事件,如果提前在研發或工廠中發現問題,純粹就只是一個工程的問題,而不會是對簿公堂,變成競爭者攻擊的話題,它所損失的絕對超過產品本身召回的金額。

那麼,如果可以越早的找到臭蟲,我們就可以降低已知問題的維修成本,進而降低產品推出後工程問題的風險。因此,對於自己的產品,我們佈下了天羅地網的測試系統,就是為了能夠及時的將臭蟲給抓出來,也確保問題不會重複發生(Safety Net)。

Coding 的階段來看,最早能夠貢獻的測試系統之一,就是 Unit Test。身為一個測試系統,其實目的和其他層次的測試系統是一樣的。不過因為它和 Source Code 能夠較為緊密結合,底下的效益是我認為可以彌補其他層次所不足:
  • Fast Feedback Loop:如果你在修改一段安裝檔的程式碼,好死不死每次安裝都要一個小時的時間。你會選擇每次修改之後就直接來一次整合測試,還是會先把修改部分的邏輯先獨立出來先測試完畢,然後再來整合測試?通過 Unit Test 先把無關的外部模組排除,模擬直接相關的外部模組,加速目前專注範圍的開發和除錯。
  • Early Defect Detection:小範圍獨立運作的程式碼,會比獨立運作的整個系統來的容易控制。如此一來,小範圍的待測物會有更多的機會可以模擬出整合測試不容易做出的測試條件。舉例來說,不同的 File System 列舉目錄下的檔案的規則可能都不相同,要測試如此的條件必須要有不同的真實環境,測試準備工作也需要比較多的時間去建置。通過 Unit Test,模擬難以由整合測試做出的測試案例,提前評估待測物的行為。
  • Safety Net for Developer:人是容易犯錯的動物,一個模組隨著時間的演進,可能會有許多的極端的測試案例被發現。若是案例可以盡可能的加入現有的 Unit Test,最終 Unit Test 可以變成一個檢核表,提前評估是否程式碼的修改影響任何測試案例。
對於 Defect Detection 和 Safety Net,注意我這裡講的是提前評估。最終來說它還是無法成為終極的測試銀彈,它能夠提供的還是有其限制。Unit Test 互動的都是我們設計好的測試鷹架(Test Scaffolding),無法代表真實系統整合後的運作情況;使用者介面也是一個 Unit Test 無法收服的領域。

我觀察到一些初入行的程式設計師,可能同時在多個模組上修改程式碼後,一口氣用手動的方式整合測試來觀察運作結果。通常的狀況就會變成:如果有問題,要花時間確認是哪個步驟出錯,修正程式碼,然後再重來一遍整合測試。或是看似沒有問題,是其實某個模組已經出錯,只是沒有明顯到出現在整合測試上面,這種臭蟲未來會更難以處理。

我認為,Unit Test 的策略非常適用於改善開發流程。先對所修改的個別地方做獨立測試,然後才是一輪整合測試。這樣的工作流程改善的是「尋找有問題的模組的時間」,並減少不必要的「整合測試運行的次數」。數據顯示,除錯常超過程式設計師工作時數 50% 以上,這樣的改善相信能夠影響工程師的生產力。

實務上,Unit Test 要怎麼做,要做到什麼樣的程度,其實不必太死忠於流程或是規範,矯枉過正,最後還是團隊受傷害。時常回頭看看動機,讓團隊決定怎麼做、怎麼評估,交由團隊做出承諾。

No comments: