軟體測試該怎麼做?
資源受限時,還可以怎麼測?
十多年前我去補習班進修日語,本來以為我有用 Anki 軟體來背單字,自己的日語水準應該在班上的程度可以得第一了吧?而我錯了,班上的哈日族同學,每天都在看日劇與動漫的,講起日語的流利度比我好上許多。
那年,同學們與日文老師很要好,假日也會約日文老師出來一起吃宵夜。有一回,我跟日文老師講,我覺得班上的哈日族同學的日語好得不得了,日文老師卻表示了不同意。老師的說法是,某同學的日語,很多都是從日劇或是漫畫學來的,直接應用的話,是勉強聽得懂沒有錯,但一方面不夠精確,一方面粗俗又有力,再加上某同學是個女性,卻使用了大量的男性用語。換句話說,學習主要靠日劇與動畫,是速成沒有錯,但是缺乏品質控管---語言能力的品質堪慮。
從事軟體工作多年,十幾年來,業界常見的事情是:「軟體因為追求速成,品質往往堪慮。」前些日子在 twitter 上看到資深工程師在討論,『軟體測試該怎麼做?』我不禁心想,這個重要議題,多數的工程師卻沒有共識,也難怪許多軟體的品質堪慮了。
軟體測試該怎麼做?有很多不同的主張。有的人主張要做單元測試,認為說有做單元測試才能確保每一個小的單元的正確性,日後如果要重構,也可以放心地重構。有的人主張要做整合測試,因為對使用者來講,整個系統正確才算是正確,即使說整合測試要自動化常常會相對的困難。也有人主張要「測試驅動開發」,因為邊改邊測,才能讓開發人員認真地把抽象層的規格定義正確。
依賴注入
我曾經做過一分工作,該工作是幫一家 CDN 公司開發主機監控系統 (server monitoring system),由於該 CDN 公司的主機數量很多,該系統我們採用 Open-Falcon 為基礎來做延伸開發。我有聽過一個諷刺的說法:「好的工具很重要,因為好的工具讓你學到很多,而不好的工具會讓你學到更多。」在那一分工作,我被迫認真思考了很多軟體開發的議題,因為 Open-Falcon 就是一個很不好的工具。
Open-Falcon 軟體本身就充滿了變通之道 (work around):
它可以讓使用者上傳一些 script ,並且自動同步到所有的 Agent ,由於這些 Agent 布署在每一台要被監控的機器上,script 就可以很容易就取得各種機器的數值。但是,自動同步的這個部分,Open-Falcon 使用
git clone,所以只要網路環境稍差,git clone就會鎖死。Open-Falcon 的文件並沒有詳細地列出,該軟體需要的所有依賴項目,換言之「依賴宣告」做得並頗差。
它有一個 Judge 模組,可以做警告 (alert) ,但是,Judge 模組並沒有足夠的可擴充性,很多需要的警告寫不出來。網路上有人把 Open-Falcon 做了超大的修改,改成與 Riemann 做整合,就是為了處理這個設計不良。
Agent 與主系統溝通的傳輸協定,也沒有可擴充性,也因此,要改的話,就要整組改掉。
還有一點造成了我那時開發的許多痛苦,整個 Open-Falcon 並沒有「依賴注入」的設計,也因此,當我開發新功能或是修改舊功能時,我並沒有簡單的方法可以做單元測試,根本沒有那個選項。很多時候,我要抓出錯誤,都是要布署整個系統之後,再用 tcpdump 去看到底封包是長什麼樣子。
主管宣稱,開發 Open-Falcon 的團隊,想必一定有一個測試團隊,有神奇的測試專用的軟體可以確保 Open-Falcon 的正確性。我居然還半信半疑地相信了他的說法,真是好傻好天真。
最少劑量測試
後來,我待的軟體接案公司 (software agency),水準相當高,依賴注入是人人都會,然而,只有依賴注入還不足以克服軟體品質的挑戰。
在接案公司工作,我們總是要加入客戶的團隊,快速掌握客戶的軟體系統,然後開始增加客戶的產出。由於客戶也是新創公司,前進的速度相當快,接受了大量軟體使用者的反饋後,需求大變更的頻率平均 3~5 個月就來一次,因此,也不可能寫高覆蓋率的測試,只能先寫最少劑量測試 (minimum dose testing),覆蓋率要等日後產品獲利增加後,才能逐步增加。
該怎麼做好最小劑量測試呢?測試要做在系統之中『相對不太會改動』的部分。
作法
程式碼拆成 policy 與 mechanism 。policy 模組與 mechanism 模組各自有自己的 API。 參考的影片連結。
API 是模組裡裡『相對不太會改動』的部分,因為下游的模組的運作都依賴於 API。
對 API 寫測試。
在 mechanism 的程式碼,試著多寫一些 property test
測試與軟體品質
寫測試是為了追求軟體品質,而軟體品質有幾種不同的層次:
正確的抽象層
可測試的抽象層
有覆蓋率高的測試,可以做到自動化驗証,節省人力
(1) 的重要性大於 (2),(2) 的重要性大於 (3) 。如果做到了 separation of policy and mechanism,通常距離 (1) 就不遠了。如果有做到「依賴注入」,那就算是做到了 (2) 。有了 (1) 與 (2) ,系統才能在演進過程之中,順利地加上覆蓋率高的測試而不需要砍掉重練。


