透過建構測試案例來定位錯誤#
你常常可以透過撰寫適當的測試來精確定位甚至修正一個 bug。有人稱這種方法為 DDT(Defect-Driven Testing),缺陷驅動測試。這個方法包含三個步驟:重現、簡化、固化。
步驟一:建立可靠重現的測試案例#
首先,建立一個能可靠重現問題的測試案例。這意味著你需要明確指定:
- Process(流程):觸發問題的操作步驟
- Materials(素材):所需的測試資料
例如,載入某個檔案後按下特定按鍵組合導致應用程式崩潰,或是將某個負載平衡器放在應用程式前面導致使用者認證失敗。
步驟二:將測試案例簡化到最小#
第二步是將測試案例簡化到最小程度。有兩種方法:
- 由下往上建構(Building up):從零開始逐步加入元素,直到 bug 首次出現
- 由上往下精簡(Trimming down):從完整的大型測試案例中逐步移除元素,直到 bug 消失
在許多情況下,你可以結合兩種方法:先盡量移除無關部分,一旦你認為知道問題所在,就從頭建構一個最小測試案例。測試案例的簡化過程本身往往就能指向問題的根源。
步驟三:將測試案例固化為自動測試#
隔離出問題後,把握機會將測試案例轉化為對應的 unit test 或 regression test:
- 如果錯誤位於獨立的程式碼部分,就加入 unit test
- 如果是多個因素組合導致的問題,regression test 更為合適
- 在 bug 尚未修復時執行測試,確認測試確實能捕捉到問題
- 修復 bug 後再執行測試,確認測試通過
即使問題已經修復,加入測試仍然重要。它能防止同樣的錯誤在未來透過 merge conflict 或其他方式再次出現,也能捕捉到相關的錯誤。
善用測試覆蓋率工具#
使用 test coverage analysis 工具來了解哪些程式碼被測試覆蓋、哪些被跳過:
- C/C++:
gcov - Java:JCov、JaCoCo、Clover
- .NET:NCover、OpenCover
- Python:
coverage - JavaScript:
blanket.js
重點回顧#
- 建立可靠且最小化的測試案例,其簡化過程本身就能引導你找到錯誤根源
- 將測試案例嵌入軟體中,作為 unit test 或 regression test 永久保存