Asynchronous Behavior
今天介紹第2種造成測試案例時好時壞的問題:「Asynchronous Behavior」(非同步行為)。如下圖所示,以現在很流行的Ajax呼叫為例,當Browser透過Ajax的方式呼叫後方的某個DAO Service(資料存取服務)之後,在資料還沒有傳回Browser之前,Browser同時間還可以處理他的事情 。這種呼叫就叫做非同步的呼叫。
那為什麼非同步的行為會導致測試案例時好時壞呢?請參考下圖,因為呼叫者(Browser)不知道對方要執行多久才會把資料傳回來,所以在撰寫測試案例的時候,如果等待的時間太短,資料還沒有回傳,那麼測試案例就會執行失敗。
請看以下這段虛擬碼:
doAsyncCall(); sleep(aWhile); readResult(); assertResult();
如果鄉民們的測試案例寫成上面這個樣子,那麼當測試案例失敗的時候,通常都是設定等待的時間(sleep)太短了,需要增加。但是,如果sleep太長,則測試案例就會跑得很慢,例如答案可能1秒就算好了,但是你卻等了60秒才去檢查,這樣也不行啊。
處理非同步行為
針對非同步行為的測試,Martin Fowler提出兩點建議:
- 使用callback
- 使用polling
doAsyncCall(); startTime = Time.now(); while(! responseReceived) { if (Time.now() - startTime > waitLimit) throw new TestTimeoutException(); sleep (pollingInterval); } readResult(); assertResult();
簡單的說,使用polling的方式,一開始先檢查資料是否已經傳回來了,如果沒有,看看是否已經等到timeout(等太久了都還沒讀到資料),如果等到timeout,則表示測試失敗,丟出一個TestTimeoutException例外。如果還沒等到timeout,則小睡片刻。採用這種方式,可以將sleep的時間設短一點,反正這次如果讀不到資料,小睡片刻之後還可以再讀一次,一直到timeout為止。如此一來可以避免一直調整sleep時間,或是將sleep設太長導致測試案例執行間太久的問題。
但是使用polling也不是完全都不需要調整時間,至少需要調整timeout的時間,因為如果timeout時間設太短,則資料還沒傳回來就已經timeout了,這樣也不行。
好難測啊
遇到這種非同步的測試,的確是滿頭大的。有一個關於測試的技巧叫做Humble Object pattern,大意是說如果鄉民們的程式邏輯處在一個不容易測試的環境當中,鄉民們就要想辦法把這個邏輯從環境中隔離(抽離)出來。換句話說,想辦法把重要的邏輯能夠用同步呼叫的方式來進行測試,那麼必須被以非同步呼叫來測試的內容或是機會就比較少了,相對地出問題的機率也會降低。
***
友藏內心獨白:有時候timeout的數值也是要調好久測試案例才會穩定啊 。
沒有留言:
張貼留言