robolectric使得可以在jvm中運(yùn)行android代碼。
Question 1
一般而言,在使用robolectric對(duì)activity中的方法進(jìn)行測(cè)試的時(shí)候,需要先setup出一個(gè)activity對(duì)象,然后來調(diào)用這個(gè)activity對(duì)象的方法,或者通過這個(gè)activity對(duì)象去findViewById一個(gè)View,然后performClick,模擬點(diǎn)擊這個(gè)view。
Robolectric.setupActivity(RoboActivity.class);
文檔中并沒有任何注釋。大概猜測(cè)這個(gè)方法在執(zhí)行后,會(huì)走activity生命周期的onCreate,onResume等方法,并將context傳入。(大概類似手機(jī)點(diǎn)擊打開了這個(gè)界面)那么,問題來了,在執(zhí)行其生命周期方法時(shí),大量的外部依賴如何解決。
前提:由于Application里面有不少加載so庫,初始化等的方法,故使用
@Config(constants= BuildConfig.class,sdk=21,application= RoboApplication.class)自己定義一個(gè)空的BaseApplication來代替。
在執(zhí)行onCreate方法時(shí),大多android相關(guān)的代碼可以正常執(zhí)行,但一旦涉及到application的,比如mSpu=newSharedPreferencesUtil(UIUtils.getContext());
UIUtils.getContext()的操作需要去獲得一個(gè)application 的context,由于Robolectric模擬的是RoboApplication的啟動(dòng),并沒有去啟動(dòng)app自身的application,因此這個(gè)context獲取的是null。導(dǎo)致后續(xù)關(guān)于sharedPreference的所有操作無法執(zhí)行。
如果RoboActivity是一個(gè)普通對(duì)象,那么可以通過依賴注入,把sharedPreference通過構(gòu)造函數(shù)傳入,在傳入時(shí),把sharedPreference 進(jìn)行mock就行了。(這就是所謂的隔離了sharedPreference這個(gè)依賴?)但這是activity,如何隔離這個(gè)依賴?
隔離不了這些依賴,是否對(duì)于這樣一個(gè) 上千行的activity,就無法對(duì)其進(jìn)行測(cè)試了?
Question 2
//用于robolectric進(jìn)行測(cè)試的方法,待修改為正常方法? //FIXME: 17/8/11
public voidsetLayoutParamsTest(RelativeLayout rl_college_list_img) {
rl_college_list_img.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,UIUtils.getScreenWidth((Activity)mContext)/2));
}
某日需求變更,需要將列表展示的圖片高度調(diào)整為屏幕寬度的一半,于是在Adapter里面寫了上面這個(gè)方法,結(jié)果運(yùn)行后崩潰。發(fā)現(xiàn)rl_college_list_img處在LinerLayout中,因此會(huì)有LayoutParams cast Exception。這一過程經(jīng)歷了運(yùn)行,然后再手動(dòng)點(diǎn)擊到修改頁面,才發(fā)現(xiàn)問題。心血來潮,如果用單元測(cè)試是否可以不用這么麻煩,直接單測(cè),十幾秒內(nèi)就發(fā)現(xiàn)問題呢。于是對(duì)Adapter進(jìn)行測(cè)試,并創(chuàng)建上面的方法。Run ~?
竟然通過了。
有點(diǎn)崩潰。debug發(fā)現(xiàn) 好像真的就只執(zhí)行了這個(gè)方法中的一部分
requestLayout();的執(zhí)行似乎沒有效果(debug得不仔細(xì),只是推測(cè)),因此并沒有上層父布局Linerlayout的onMeasure操作,而這個(gè)異常就是由onMeasure調(diào)用measureVertical后拋出的。
心態(tài)崩了... ? ?這也測(cè)不出來,要你何用。
所以到底如何能夠讓大多數(shù)方法可測(cè)呢?就像小創(chuàng)說的效果:
”節(jié)約時(shí)間:對(duì)于安卓開發(fā)來說,一遍一遍的運(yùn)行app,再執(zhí)行相應(yīng)的用戶操作,看界面是否顯示正確的結(jié)果,通過這種方式來測(cè)試自己的新代碼、重構(gòu)是否是正確的,這是非常浪費(fèi)時(shí)間的一件事情,而且效果還不好。有了單元測(cè)試,我現(xiàn)在開發(fā)過程中幾乎已經(jīng)不用把a(bǔ)pp運(yùn)行起來了,速度相對(duì)來說快多了。“http://www.lxweimin.com/p/68212278f592
感覺完全辦不到啊,任何一個(gè)ui上的改動(dòng),都似乎要運(yùn)行起手機(jī)。
后期再看看有沒有使用空間,不然真的要棄坑了...
8.15更新:
Advantage1:
吸收大神的經(jīng)驗(yàn),盡量用隔離android代碼與java代碼,然后用junit4對(duì)java進(jìn)行測(cè)試。今天抽出一個(gè)model層,將異步網(wǎng)絡(luò)請(qǐng)求request類放入這層。 model層應(yīng)該是不會(huì)含有任何android 代碼的,ok,寫好
run~。 fail了。'java.lang.RuntimeException: Method isEmpty in android.text.TextUtils not mocked'錯(cuò)誤。 ok,doRequest里面用到了 android的TextUtils類。
http://www.lxweimin.com/p/f5d197a4d83a,根據(jù)鍵盤男 的這個(gè)經(jīng)驗(yàn)...在test/java目錄下,創(chuàng)建android.text.TextUtils類.
繼續(xù)run~fail again
好吧,用了一個(gè)全包全能的xutill來做網(wǎng)絡(luò)請(qǐng)求就是坑,里面還用了looper。這下就很難用Junit4來測(cè)了。 這時(shí)候想到了Robolectric,加上Robolectric的注解,run,passed。
好的,看來Robolectric有時(shí)候還挺有用的,對(duì)于我這個(gè)渣項(xiàng)目來說還管用。
(僅僅對(duì)問題進(jìn)行記錄,如果了解決方法再更新。有大神路過請(qǐng)不吝解答^_^)
這樣一來是不是只能用 AndroidJunit 、Espresso了