基于Android的C/S移動應用中訪問后端數據的場景是非常多的,異步接口測試主要是在單元測試完成的基礎上檢查接口級訪問是否正確,主要保證對外請求的組裝與發送是否符合后端的約定?,F在項目的異步接口訪問都遵循一個特定的訪問模式:前臺的Activity獲取到觸發事件后將接受到的參數傳給一個異步任務,這些任務大都是AsyncTask的實現——即啟動一個新的線程訪問后臺接口數據,完畢后調用回調函數更新UI展示,示意圖如下:
一. 測試框架
對于Android中這種異步接口的自動化測試需要解決3個問題:
1) 如何獲取到異步任務執行結果;
2) 如何讓上層測試代碼盡量不處理任務等待;
3) 如何處理需要登錄的接口。
對于問題1)每個異步任務在獲取結果后就直接調用onPostExecute()方法了,測試代碼獲取不到結果,所以必須有一個專門的樁Activity負責異步任務的執行并將結果暴露出來;
對于問題2)盡量將等待操作交給測試基類,上層測試代碼只需要執行被測邏輯而不需要關心細節;
對于問題3)采用模板模式,如果接口需要登錄則先執行登錄操作后再調用,整體解決方案如下:
先介紹樁Activity,它負責異步任務的實際調用,同時承擔分發器的作用,如果需要登錄則先分發給需要登錄的流程,不需要登錄則直接調用不需要登錄的流程。當然它還有重要作用就是取到異步接口調用后的結果,這樣Test Case獲取到并比對結果,示意代碼如下:
可以看到isCompleted是標識異步任務是否執行完畢的,無論異步任務返回是onSuccess、onError還是 onIOException都會進行置位;result則是異步調用的返回,可以看到這里無論接口調用是成功、失敗還是io異常都會將這個結果暴露出來以使測試代碼能夠獲取到。
然后介紹InterfaceAction,它是測試代碼需要實現的接口,內容如下:
前兩個接口實現是為其服務的,如果訪問的接口必須處于登錄狀態則讓neddLogin()返回true同時實現login()的邏輯,不需要登錄則直接讓 neddLogin()返回false即可。而action()是核心測試邏輯,包括發送數據的準備和實際接口的調用。
最后介紹的是測試用例都需要繼承的測試基類,他主要為了減少對異步任務等待的代碼以及顯示對InterfaceActivity這個樁Activity的調用,示意代碼如下:
這樣上層test case只需要關心具體的測試邏輯而不用關心異步調用及等待處理,只需要取到返回的result進行斷言。
二. 測試代碼示例
首先介紹一下測試用例的組織形式,一共分為兩層:action層和test case層,action層為異步調用邏輯層,所有的類都實現InterfaceAction,case層為測試用例層,主要組裝各種action并斷言結果,如下圖所示:
為了使示例能夠簡單明了地表達意圖,假設我們要測試Bar接口(需要登陸),BarAction是實際操作,BarTest是測試用例:
這里BarAction繼承于BaseLoginAction,它默認實現了needLogin()和login()方法,這樣BarAction 本身就不必關心登錄邏輯了。當然更好的寫法是“common”和“bar”這些測試數據從params中取,這樣就可以從測試用例層直接傳遞測試數據過來。接下來是BarTest的實現:
測試類主要是對BarAction的調用,它可以向接口傳遞不同的參數,同時也可傳遞登錄信息。asyncInvoke(action)完成了接口邏輯的調用及時間的等待,測試代碼只需著重關注result并進行斷言。
三. 總結
異步接口的集成測試的側重點在于Android手機端向服務器端發送的請求是否正確,以上測試Case的斷言與后端數據其實是強耦合的,即后端 bar這個賬戶的數據變化可能導致Case的fail,所以可以考慮引入hamcrest包,做一些匹配校驗,主要測試正常和異常情況服務器返回的內容是否符合預期,比如上面最后一個斷言可以寫成:assertEquals(resp.getResult() (), greaterThan(0));當然,服務器端接口的正確性正常情況下應該由服務器端的自動化Case來保證,這樣才不至于前后端測試緊耦合在一起。
原文轉自:http://qa.baidu.com/blog/?p=1021