l

2012年12月5日 星期三

對付時好時壞的測試案例(5):Time

Nov. 27 21:02~22:04

image

 

Time

第四種造成測試案例時好時壞的原因稱之為Time(時間),相對於前三種原因,因為時間所造成的測試案例錯誤發生機率較少,但是這種問題一旦發生有時候不太容易被發現或是不太容易解決。舉個例子,有些人會利用getTime()這樣的函數來產生ID或是序號。在某些電腦上,這種方式所產生的ID永遠都不會重複。但是相同的程式拿到速度比較快的電腦中,便有可能產生重複的ID(因為電腦跑太快了啊,連續呼叫兩次getTime()可能會傳回相同的值。這種事情,Teddy也曾經遇過)。

依據Martin Fowler的建議,程式裡面最好不要直接呼叫使用系統時鐘(system clock)的函數。因為如果直接去呼叫system clock函數,每次呼叫所得到的值都會不同,這樣的程式是很難被測試的。舉個例子,假設鄉民們的程式有一個功能需要列出「這禮拜的營業額」。鄉民們可以先在資料庫中建立好若干筆交易資料,但是現在問題來了,如果在程式中直接呼叫時間函數取得「這禮拜」的時間,哪麼每個禮拜執行這隻程式所傳回的「這禮拜」都會不一樣,因此每次得到的「這禮拜的營業額」也會不同。

看到這邊鄉民們可能會想:「我可以每次執行測試案例的時候,重新產生一次這禮拜營業額的假資料啊,這樣子測試案例就不會有問題了」。這也是一種方法,但是如果我們可以只產生一次假資料,然後在執行「這禮拜的營業額」的測試案例的可以,可以inject(注入)一個指定的時間到測試案例中,這樣子就可以避免每次都需要重新產生新的測試資料。

怎麼做

解決這個問題最簡單的作法,就是如果程式中有需要用到和時間相關的計算,考慮一下有沒有可能把時間當成參數傳進來,而不要直接寫死在程式裡面。請參考下面這個例子:

getThisWeekRevenue();  ---> 在程式寫死,自己呼叫系統時間取得這一週的日期。

getWeeklyRevenue(Date aDate); --->哪一週由呼叫者傳入



另一種情況是程式中如果真的需要直接呼叫到類似SystemClock物件中的函數,請幫這個物件打包一層,定義一個類似ISystemClock的介面(可以用Extract Interface這個refactoring方法,將SystemClock的介面抽離出來),然後再寫一個DefaultSystemClock來實作ISystemClock介面。DefaultSystemClock可以包含一個SystemClock物件,然後將所有實作直接轉呼叫原本的SystemClock物件。在測試案例中,可以自己產生一個MockSystemClock取代DefaultSystemClock,以達到控制時間的目的。



***



友藏內心獨白:不是只有上帝才可以控制時間嗎 XD。

沒有留言:

張貼留言