2015年1月17日 星期六

學習 Unit Test 之一

為了重構一個專案既有程式碼,開始了重構的學習歷程,這些文章會把一些學習與實作中的心得記錄下來。剛開始深入研究的自己,也估不出來會用上多少篇文章來記錄,就估且用數字來的編號,等到未來遇到更好的文章命名方式,再回頭調整吧!

開始的篇章想先記錄的,是花了一兩個星期看完 Apache FlexUnit 指引之後的感想。作為一個成名已有兩三年以上的技術,在學習上並沒有我想像中的那麼容易,一些套件的名稱有了改變,原有的範例程式不能執行,或是舊版的函數庫已經找不到,得所有函數庫都升級到最新的版本。作為一個已經一段時間新東西可討論的技術,往往看到的都是數年之前的文件,當遇到問題,無人可問的無助感在心頭揮之不去。

所謂的「單元測試」,就如同其名一般只針對「單元」進行測試,所以雖然它也能夠發展成為某些「功能測試」的工具,但並不是它的設計初衷。從前的我一直認為「單元」只是表示它的測試「能夠細到每一個小單元」,並且對於每一項測試並不保證順序,以及每一次的測試都需要重頭執行測試項目初始化感到不解,認為它會造成在測試上的一些不確定性。


所以單元測試在我的心中,一直是一個神奇,但並不是很理想的工具。在沒有時間好好學習的前幾年,曾經試著自己寫自己的測試程式,在沒有看到什麼明顯的幫助,加上開發時程急迫的關係,最後沒有持續寫下去,一直等到幾個星期前,有了時間開始好好學習它。

在學習的過程中,常常遇到照著範例上的內容打,但是程式卻跑不起來的情形。不少次看著一段語義不詳的錯誤訊息,花了幾個小時的時間在網路上找尋答案。引用的套件不只一個,偏偏不知道發生錯誤的哪一個。是因為自己程式輸入出了問題?還是不同時期釋出的套件之間不相容?又或者是文件舊了,新版的寫法有改變?同樣的問題誰有可能,但都不能肯定是誰造成的。

停下來,不再繼續後續的章節,先專心處理眼前的任務,到 github 上去查框架的原始程式,看著一段又一段的程式碼,去猜測問題發生的原因,感覺回到了剛入社會時的工作內容,就是看著一行行程式,去思考它背後的運作原理,接著再進行除錯或是增加功能。進度很慢,一天大約只能看完一兩篇。現在回頭看看這個過程,剛好是的現在大多程式人員工作的縮影,想辦法看懂既有的程式碼,再完成被交付的程式工作。

既然是成名已久的專案,應該不會出現造成連範例程式都跑不動的低級錯誤。但是已經找不到和範例相同版本的函數庫。所以一旦錯誤訊息包含的資訊不足,就會面臨到不知錯從何來的狀況。在不知道如何在已經打包的函數庫中加上 trace 程式輸出資訊到 console 的前提下,只能不斷的修改既有的測試程式,看看哪一種組合才是能跑出和範例一樣的結果。

如果,能夠將範例程式執行的流程,分成一段一段,每段只需要一種函數庫,這樣應該可以更快找到問題,並且解決它。當時沒有注意到這樣子的想法,歪打正著的符合單元測試的「一次只測試一個部分」精神。理由很簡單,當可能發生問題的地方變多了,要正確找到問題發生點也跟著變得不容易。

因此,要排除在測試上造成結果不同的因素。可能是另一個還沒完成測試的類別,所以有模擬類別的技術。也可能是其它測試造成的結果,因此每一次測試都被要求獨立,不互相干擾,如此一來每個測試的執行順序也不再重要。在一連串的技術與工具使用,單元測試的目的,不單單是測試程式是否如同設計中的運作,也希望在發生錯誤的時候,可以藉由測試的項目,指出造成問題的地方,能夠更容易地被修正。

所以單元測試的應該縮小範圍,專注於每一個「單元」,對於由多個未通過測試的單元組成的程式進行檢測,既使發現出錯,也無法立刻肯定的指出問題的原因,所以如果遇到程式邏輯過於複雜的程式,就輪到「重構」出場了。一個被好好重構過的程式,不單適合被其它工程師理解,也通常適合拿來進行單元測試。

沒有留言:

張貼留言