前言
近期我對自己看待撰寫程式這件事有更高的期許,除了最基本的效能、閱讀性、擴充性……之外還有一個非常重要的領域就是:測試。
不過程式好端端的能動就代表測試沒有必要了嗎?在我剛工作時實際上做了一段時間的自動化 QA 工程一段時間,不過那時候的我其實也並不明白寫測試的原因,就是有程式就拿來自動化測試,並沒有想太多。
這篇就是適合寫給沒有測試經驗想入門的人,目標對象差不多就是我先前的自己。
為什麼要測試?如何發揮測試的價值?
寫測試是一件好事對吧?可以自動的驗證程式的行為,確保程式的正確性,這樣就不用每次都要手動測試了,可以透過自動化來節省手動測試。
這是我最初的想法,然後就一頭栽進去寫很多測試,花大把的時間替每個功能都加上測試,然後發現……沒發揮什麼作用。
一、測試只在被執行時才有價值
一個程式的價值體現在它被執行使用的時候,而一段測試的價值也體現在它驗證了程式的某個行為的正確性;就算程式架構得再爛但因為可以運作所以持續的產出價值,同理一段測試再完美但因為沒有驗證到任何行為所以是沒有價值的。
我犯下最大的錯就是單純寫了很多測試但沒有積極的去執行,讓測試盡量跑起來,驗證程式的行為就是測試的價值所在,成功的測試帶給你信心,錯誤的測試替你抓 BUG。
這裡的信心是指確定程式如預期般的行動,你會更有自信的去架構代碼並確保改動不會對被驗證過的的行為造成影響。將測試導入開發流程的重要性不亞於測試本身,不會動的測試就是單純的案例文件,有人沒事會去看不常用且沒有約束力的規格文件嗎?沒有!
二、測試即文件
前面提到測試其實就像是規格書,試想看看一份詳盡的規格文件,透過一些魔法可以讓這份文件可以隨時隨地自動化驗證程式的行為,提醒開發者哪裡不符合預期……這不就是測試嗎?
測試本質上就是一種自動化規格書。開發與測試並不是兩個世界而是相輔相成的關係,反覆的「事先」寫下對程式的期望測試並實踐,一直重複這樣的流程你就發現了 TDD (Test Driven Design)測試驅動開發!這種做法就不會讓測試與規格脫節,因為測試就是規格。
但在這裡仍然是工程師寫下自己的期望並反覆迭代出可以被自動化驗證正確性的程式,商業人士也有他們自己的規格書要寫,把大家的文件整合為一種依照行為而不是實作細節為主的規格書,並在根據演進為其加上測試、實作細節,這就是 BDD (Behavior Driven Design)行為驅動開發。
「測試即文件」的意思是希望換一個思維去接受測試,不要把測試當成是一種負擔,而是在開發層面上了解實作是「結果」但在這之前「原因」也相同重要。
三、撰寫測試是為了更高的效率
節省時間: 有些種類問題測試起來費時費力,可能會需要刁專的模擬使用者進行特定的操作或權限、等待畫面讀取、驗證畫面元素、驗證各式各樣種類的狀態……會需要大量人工時間的,或是很難透過人工來達成,算下來自動化測試就是值得的投資。
降低風險: 或是說有時候程式重要到一丁點錯誤都不能犯下(金錢交易、性命攸關),那麼測試也可以幫助你確保程式的正確性,算下來減緩開發速度確保每件事都正確運作也是值得的。
總結
測試是個充滿爭議的話題,靈活性與正確性你選誰?是先有良好的規格再實作,還是先實作再補上規格?這是一個永遠存在的問題。有人寧願犧牲靜態檢查、也有人認為測試是必要嚴格且優先於實踐。背後其實已經不只是技術,而是整個團隊文化、產品要考慮的問題。
我可以確定一件事:沒被測試的程式不是非常簡單需要快速迭代(尚不清楚價值),就是變成沒人曉得如何運作的義大利麵(有價值但你害怕改動),這兩點的平衡也是藝術。
遺留程式碼(Legacy Code)是指害怕更改的有價值的程式碼