這是我在InfoQ組織的移動開發前線微信群里面做的一次分享,發到簡書上面一份,希望給在簡書有需要的讀者也能提供一點幫助,以下是原文:
大家好,我是蘑菇街支付金融部門的小創。今天很高興跟大家分享一下安卓的單元測試在蘑菇街支付金融的實踐。下面,我們從為什么開始。
為什么要寫單元測試
首先要介紹為什么蘑菇街支付金融這邊會采用單元測試的實踐。說起來比較巧,剛開始的時候,只是我一個人會寫單元測試。后來老板們知道了,覺得這是件很有價值的事情,于是就叫我負責我們組的單元測試這件事情。就這樣慢慢的,單元測試這件事情就成了我們這邊的正常實踐了。再后來,在公司層面也開始有一定的推廣。
要說為什么要寫單元測試的話,我相信大部分人都能承認、也能理解單元測試在保證代碼質量,防止bug或盡早發現bug這方面的作用,這可能是大家覺得單元測試最大的作用。然而我覺得,除了這方面的作用,單元測試還能在很大程度上改善代碼的設計,同時還能節約時間,讓人工作起來更自信、更開心,以及其他的一些好處。這些都是我的切身感受,我相信也是多數真正實踐過單元測試的人的切身感受,而不是為了宣傳這個東西而說的好聽的大話。
說到節約時間,大家可能就會好奇了,寫單元測試需要時間,維護單元測試代碼也需要時間,應該更費時間才對啊?
這就是在開始分享之前,我想重點澄清的一點,那就是,單元測試本身其實不會占用多少時間,相反,還會節約時間。只是:1. 學習如何做單元測試需要時間;2. 在一個沒有單元測試的項目中加入單元測試,需要一定的結構調整的時間,因為一個有單元測試跟沒有單元測試的項目,結構上還是有較大不同的。
打個比方,開車這件事情,需要很多時間嗎?我相信很少人會說開車這件事情需要很多時間,而是:1. 學習開車,需要一定的時間;2. 如果路面不平的話,那么修路需要一定的時間。單元測試也是類似的情況。
那為什么說單元測試可以節約時間呢?簡單說幾點:1. 如果沒有單元測試的話,就只能把app運行起來測試,這比運行一次單元測試要慢多了。2. 盡早發現bug,減少了debug和fixbug的時間。3. 重構的時候,大大減少手動驗證重構正確性的時間。
所以,我希望大家能去掉"沒時間寫單元測試"這個印象,如果工作上安排太緊,沒有時間學習如何做單元測試的話,可以自己私底下學,然后在慢慢應用到項目中。
單元測試簡單介紹,以及void方法怎么測
接下來介紹我們這邊是怎么做安卓單元測試的。首先澄清一下概念,在安卓上面寫測試,有很多技術方案。有JUnit、Instrumentation test、Espresso、UiAutomator等等,還有第三方的Appium、Robotium、Calabash等等。我們現在講的是使用JUnit和其他的一些框架,寫可以在我們開發環境的JVM上面直接運行的單元測試,其他的幾種其實都不屬于單元測試,而是集成測試或者叫Functional test等等。這兩者明顯的不同是,前者可以直接在開發用的電腦,或者是CI上面的JVM上運行,而且可以只運行那么一小部分代碼,速度非???。而后者必須要有模擬器或真機,把整個project打包成一個app,然后上傳到模擬器或真機上,再運行相關的代碼,速度相對來說慢很多。
單元測試的定義相信大家都知道,就是為我們寫的某一個代碼單元(比如一個方法)寫的測試代碼。一個單元測試大概可以分為三個部分:
setup:即new 出待測試的類,設置一些前提條件
執行動作:即調用被測類的被測方法,并獲取返回結果
驗證結果:驗證獲取的結果跟預期的結果是一樣的
然而一個類的方法分兩種,一種是有返回值的方法。一種是沒有返回值的方法,即void方法。對于有返回值的方法,固然測試起來是很容易的,但是對于沒有返回值的方法,該怎么測試呢?這里的關鍵是,怎么樣獲取這個方法的“返回結果”?
這里舉一個例子來說明一下,順便澄清一個十分常見的誤解。比如說有一個Activity,管他叫DataActivity,它有一個public void loadData()方法, 會去調用底層的DataModel類,異步的執行一些網絡請求。當網絡請求返回以后,更新用戶界面。
這里的loadData()方法是void的,它該怎么測試呢?一個最直接的反應可能是,調用loadData()方法(當然,實際可能是通過其他事件觸發),然后一段時間后,驗證界面得到了更新。然而這種方法是錯的,這種測試叫集成測試,而不是單元測試。因為它涉及到很多個方面,它涉及到DataModel、網絡服務器,以及網絡返回正確時,DataActivity內部的處理,等等。集成測試固然有它的必要性,但不是我們應該最關注的地方,也不是最有價值的地方。我們應該最關注的是單元測試。關于這一點,有一個Test Pyramid的理論:
原文轉自:http://www.jianshu.com/p/9f7a992fe9ec