l

2012年2月23日 星期四

如何測試Singleton(2)

February 23 10:06~11:38
昨天為了三月十號的「Scrum軟體開發工具與方法 - 系列講座(六)」做了一整天的投影片,整整有快十個小時。活動的報名網址應該過一兩天就會公布了,還有一些細節還沒喬好,等報名網址公布之後再通知鄉民們,以下是當天活動的「Beta 版 搶鮮版」海報,對活動內容有興趣且當天沒有要去吃喜酒的鄉民們可以參考一下(據說當天是農民曆上的好日子,很多人要去參加喜宴…XD)。
螢幕快照 2012-02-22 下午10.40.04
***
可能是昨天用腦過度,今天有種腦袋空空的感覺(還是因為吃太飽了,剛剛「不小心」把今天中午的午餐給吃掉了…XD)想來想去今天就談一下上次沒談完的如何測試Singleton這個問題。在「如何測試Singleton(1)」中,Teddy問了三個問題:
  1. 到底設計class的時候,應不應該加上類似reset()這種「為了方便測試而存在的method呢?」
  2. 如果應該,那麼要如何避免這些為了測試而存在的methods不小心被其他人誤用?
  3. 上面這個測試Singleton問題,是否還有其他方法可以在不增加reset() method的情況下達到測試的目的?
今天先討論第3個問題。在搞笑談軟工Facebook社團中有好幾位鄉民們給了Teddy好幾個答案,基本上要讓原本程式(下圖)的測試案例可以順利執行有以下幾種方法(如果忘了原本的問題請把第一集再看一次)。
image

每次執行單一測試案例(test method)時啟動一個新的JVM
由於每個測試案例都在一個新的JVM環境中執行,所以每次執行Singleton測試案例的時候上途中的12-27行會被執行,便可以藉由設定不同的「widget_platform」環境變數來控制要產生Win32WidgetFactory或是MotifWidgetFactory。但是這個做法有一個缺點,由於每次執行一個測試案例都需要啟動一個新的JVM,所以執行速度會比較慢(路人甲:沒關係,我的電腦速度超快)。

利用Reflection或是MockObject工具重設mFactory為null
Java的Reflection機制可以讓鄉民們存取物件的私有變數,這個方法以前Teddy也有在撰寫單元測試時用過,學弟告訴Teddy「這裡」有一份資料可供參考。另外有一位鄉民告訴Teddy:「PowerMock framework裡的WhiteBox class有個setInternalState可以用來重設mFactory為null」,有興趣的鄉民們可以去試看看這個PowerMock工具 。但是這個方法也有一個缺點,就是如果程式語言沒有提供類似Java的Reflection機制去讀取私有變數的話,那麼這個解法就行不通了。

利用繼承
這也是另一位鄉民提供的答案,如果不想在待測程式身上加上reset()這種為了測試而存在的method,可以用寫一個新的類別來繼承待測程式,並且在這個子類別中實作reset(),然後在測試案例中就改測試這個子類別。但是這樣做必須要把原本mFactory由private改成protected。另外,如果原本的待測程式是設計成不允許繼承的final class的話,這一招也沒轍。

使用Nested Classes
這是由Teddy的另一位學弟所提供的方法,把test case以nested classes的方式寫在待測程式身上,如此一來便可直接存取待測程式的私有變數。缺點是test case跟production code(待測程式)會放一起,但是也有另外一派的人認為這是個優點(情人眼裡出西施嗎…XD)。

在分散式持續整合系統(CI)上跑測試案例
在本地端不要執行這個測試案例,直接丟到CI系統中讓CI系統執行。這個方法乍看之下有點賴皮,自己解不了的問題丟給別人處理,但是有時候這卻也是不得不為之的方法。例如,如果有兩個測試案例真的個別需要產生一個會呼叫到Windows與Linux平台特定系統函數的Singleton物件,那麼四種方法便無法解決此問題。像是Jenkins這種支援分散式持續整合功能的CI系統,可以讓使用者設定,把不同的測試案例分派到不同的slave端執行,如此一來便可解決此問題。但是這個解法也有一個缺點,那就是programmer無法在本地端執行這些測試案例,所以把程式碼commit到CI系統之後才會知道測試案例是否通過。換句話說,programmer可能會送交有bugs的程式到CI系統中。
以上總共提了五種可能的解法,有沒有第六種,有,不過留到下次再說明。最後Teddy還有一件事想說,以上這五個解法的實際內容,如果鄉民們看完之後還是不懂,那也沒關係,反正鄉民精神本來就是來看熱鬧而不是看門道的。重點是,Teddy想傳達一個觀念,從事軟體設計遇到問題時必須要有備案(alternatives)。設計的問題都是所謂的「取捨問題」,很難找到絕對好而沒有任何副作用或是缺點的設計(怎麼覺得跟吃藥一樣)。當遇到問題的時候,如果擁有的備案越多,越容易「在一堆爛蘋果中找到一的比較不爛的」。如果沒有能力找出任何備案,最後可能落得如此的下場:
  • 默不吭聲吞下一個無俚頭的解法。
  • 皇上聖明,皇上聖明啊…(三天後)…皇上聖明啊…。
  • 進化成派大星…呵呵…你不是方褲褲的海綿寶寶(流口水ing)。
  • 下一個老闆也許會更好。
***
友藏內心獨白:剛出爐的文章,趁熱快吃。

沒有留言:

張貼留言