不錯(cuò)的官方文檔翻譯(含作者見(jiàn)解)
這篇文章翻譯簡(jiǎn)直太棒了碳胳,本文的內(nèi)容都來(lái)自對(duì)該文章所記錄的筆記。
Android自動(dòng)化測(cè)試--Espresso框架使用
Android官網(wǎng),_科學(xué)上網(wǎng)也訪問(wèn)不了跪求原因
如何使用Espresso
- 在module級(jí)別的Gradle中添加以下配置
android {
defaultConfig {
...
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
2.添加依賴
dependencies {
androidTestCompile 'com.android.support:support-annotations:23.1.1'
androidTestCompile 'com.android.support.test:runner:0.4.1'
androidTestCompile 'com.android.support.test:rules:0.4.1'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
}
3.測(cè)試代碼編寫
一般來(lái)說(shuō)我們?cè)趍ain/java中放置主要的業(yè)務(wù)邏輯代碼欣喧,在 androidTest/java放置測(cè)試代碼.
src/
androidTest/java ----這里存放instrumentation test相關(guān)的代碼
main/java ----這里存放工程代碼
建議測(cè)試代碼的分類與被測(cè)試類放置在相同的包目錄下窗看,例如待測(cè)試的類為src/main/java/package-name/A.java榨呆,那么測(cè)試類可以放置在src/androidTest/java/package-name/ATest.java目錄下妹孙,測(cè)試類名稱以Test作為后綴.
Espresso的一些語(yǔ)法
onView() 查找元素,其完整的方法簽名如下:
public static ViewInteraction onView(final Matcher<View> viewMatcher) {}
這個(gè)方法接收一個(gè)Matcher<View>類型的入?yún)⑶锉祷匾粋€(gè)ViewInteraction對(duì)象,其所做的事情就是根據(jù)Matcher<View>所指定的條件蠢正,在當(dāng)前UI頁(yè)面上尋找符合條件的View骇笔,并且把相應(yīng)的View返回出來(lái)。這樣說(shuō)還是比較抽象,我們可以用一個(gè)具體的例子加以說(shuō)明笨触。
當(dāng)我們?cè)趯?shí)現(xiàn)布局的時(shí)候懦傍,每個(gè)控件都會(huì)有一些特殊的屬性來(lái)確定其唯一性,比如最常用的R.id芦劣。Matcher<View>支持通過(guò)控件的唯一ID來(lái)從當(dāng)前頁(yè)面上尋找目標(biāo)控件粗俱,對(duì)應(yīng)的方法為withId(),該方法定義如下:
public static Matcher<View> withId(final int id) {}
大家可以看到,該方法接收了一個(gè)int類型的入?yún)⑿橐鳎祷亓艘粋€(gè)Matcher<View>對(duì)象源梭,于是,采用如下寫法:
onView(withId(id));
我們就能在當(dāng)前頁(yè)面找到指定ID所對(duì)應(yīng)的目標(biāo)控件了稍味。
實(shí)際上,Espresso提供了很多方法來(lái)讓我們自定義我們的查找條件荠卷。比如我們可以通過(guò)withText()方法來(lái)尋找顯示了指定文案的控件等等模庐。具體支持的Matcher類型可以參考Espresso cheat sheet。
需要提醒大家一點(diǎn)的是油宜,onView()方法在根據(jù)匹配條件進(jìn)行查找時(shí)掂碱,它的目標(biāo)是找到唯一的一個(gè)目標(biāo)控件。如果我們制定的匹配條件有多個(gè)控件可以匹配(比如復(fù)用了layout的布局慎冤,或者顯示相同文字的TextView等)疼燥,該方法會(huì)拋出一個(gè)AmbiguousViewMatcherException異常,因此我們?cè)跇?gòu)造匹配條件時(shí)蚁堤,一定要確保能查找到的目標(biāo)控件是唯一的醉者。
如果單一的匹配條件無(wú)法精確地匹配出來(lái)唯一的控件,我們可能還需要額外的匹配條件披诗,此時(shí)可以用allOf()方法來(lái)進(jìn)行復(fù)合匹配條件的構(gòu)造:
onView(allOf(withId(id), withText(text)))
以上代碼可以查找ID為id同時(shí)顯示的文字內(nèi)容為text的控件撬即。這里需要注意的是,為了保證自動(dòng)化測(cè)試的效率呈队,我們應(yīng)盡可能減少匹配條件的數(shù)量剥槐。如果用一個(gè)匹配條件能夠滿足我們的需求,我們也就沒(méi)有必要再用allOf()來(lái)構(gòu)造復(fù)合匹配條件了宪摧。
操作元素
public ViewInteraction perform(final ViewAction... viewActions) {}
該方法定義在ViewInteraction類里面粒竖。還記得onView()方法的返回值么?yes几于,正是一個(gè)ViewInteraction對(duì)象蕊苗。因此,我們可以在onView()方法找到的元素上直接調(diào)用perform()方法進(jìn)行一系列操作:
onView(withId(id)).perform(click())
如上代碼對(duì)onView()查詢到的元素做了一次點(diǎn)擊的操作孩革。請(qǐng)注意岁歉,perform()方法的入?yún)⑹亲冮L(zhǎng)參數(shù),也就意味著,我們可以依次對(duì)某個(gè)元素做多個(gè)操作:
onView(withId(id)).perform(click(), replaceText(text), closeSoftKeyboard())
以上代碼對(duì)目標(biāo)元素依次做了點(diǎn)擊锅移、輸入文本熔掺、關(guān)閉輸入法鍵盤的操作。這是一個(gè)典型的填寫表單的行為非剃。
檢查結(jié)果
到目前為止置逻,我們已經(jīng)能找到元素,也能夠?qū)υ剡M(jìn)行一些操作了备绽!接下來(lái)我們需要檢查一下這些操作的結(jié)果是否符合我們的預(yù)期券坞。
Espresso提供了一個(gè)check()方法用來(lái)檢測(cè)結(jié)果:
public ViewInteraction check(final ViewAssertion viewAssert) {}
該方法接收了一個(gè)ViewAssertion的入?yún)ⅲ撊雲(yún)⒌淖饔镁褪菣z查結(jié)果是否符合我們的預(yù)期肺素。一般來(lái)說(shuō)恨锚,我們可以調(diào)用如下的方法來(lái)自定義一個(gè)ViewAssertion:
public static ViewAssertion matches(final Matcher<? super View> viewMatcher) {}
這個(gè)方法接收了一個(gè)匹配規(guī)則,然后根據(jù)這個(gè)規(guī)則為我們生成了一個(gè)ViewAssertion對(duì)象倍靡!還記得Matcher這個(gè)類型么:锪妗!是的塌西,這就是onView()方法的入?yún)⑺妫?shí)際上他們是同一個(gè)類型,其使用方法也是完全一致的捡需。
比如办桨,我想檢查一下指定id的TextView是否按照我的預(yù)期顯示了一段text文本,那么我就可以這樣寫:
onView(withId(id)).check(matches(withText(text)))
簡(jiǎn)潔明了站辉。ViewAssertion的支持也可以參照這個(gè)Espresso cheat sheet呢撞。
AdapterView
對(duì)于類似ListView這種有UI復(fù)用的元素來(lái)說(shuō),只是通過(guò)onView()就顯得復(fù)雜了一點(diǎn)庵寞,我們來(lái)看一下針對(duì)這種情況應(yīng)有何種方案狸相。
AdapterView是一種通過(guò)Adapter來(lái)動(dòng)態(tài)加載數(shù)據(jù)的界面元素。我們常用的ListView, GridView, Spinner等等都屬于AdapterView捐川。不同于我們之前提到的靜態(tài)的控件脓鹃,AdapterView在加載數(shù)據(jù)時(shí),可能只有一部分顯示在了屏幕上古沥,對(duì)于沒(méi)有顯示在屏幕上的那部分?jǐn)?shù)據(jù)瘸右,我們通過(guò)onView()是沒(méi)有辦法找到的。
對(duì)于AdapterView岩齿,Espresso提供了如下方法用來(lái)查找元素:
/**
* Creates an {@link DataInteraction} for a data object displayed by the application. Use this
* method to load (into the view hierarchy) items from AdapterView widgets (e.g. ListView).
*
* @param dataMatcher a matcher used to find the data object.
*/
public static DataInteraction onData(Matcher<? extends Object> dataMatcher) {}
我們首先來(lái)研究一下這個(gè)方法的返回值太颤。從以上定義可以看出,該方法返回了一個(gè)DataInteraction對(duì)象盹沈,還記得onView()方法返回的ViewInteraction對(duì)象么龄章?這兩者的區(qū)別可以大概描述為:
- ViewInteraction: 關(guān)注于已經(jīng)匹配到的目標(biāo)控件。通過(guò)onView()方法我們可以找到符合匹配條件的唯一的目標(biāo)控件,我們只需要針對(duì)這個(gè)控件進(jìn)行我們需要的操作做裙。
- DataInteraction: 關(guān)注于AdapterView的數(shù)據(jù)岗憋。由于AdapterView的數(shù)據(jù)源可能很長(zhǎng),很多時(shí)候無(wú)法一次性將所有數(shù)據(jù)源顯示在屏幕上锚贱,因此我們主要先關(guān)注AdapterView中包含的數(shù)據(jù)仔戈,而非一次性就進(jìn)行View的匹配。
我們?cè)賮?lái)研究一下這個(gè)方法的入?yún)⑴±取囊陨隙x看出监徘,該方法接收了一個(gè)Matcher<? extends Object>的參數(shù),該參數(shù)用來(lái)指定一個(gè)匹配規(guī)則吧碾。還記得onView()的入?yún)⒚椿丝渴且粋€(gè)Matcher<View>對(duì)象。從類型上來(lái)看倦春,這兩者的區(qū)別也不言而喻:
- Matcher<View>: 構(gòu)造一個(gè)針對(duì)于View匹配的匹配規(guī)則廊蜒;
- Matcher<? extends Object>: 構(gòu)造一個(gè)針對(duì)于Object(數(shù)據(jù))匹配的匹配規(guī)則。
從以上對(duì)比可以看出溅漾,我們?cè)谑褂胦nData()方法對(duì)AdapterView進(jìn)行測(cè)試的時(shí)候,我們的思路就轉(zhuǎn)變成了首先關(guān)注這個(gè)AdapterView的具體數(shù)據(jù)著榴,而不是UI上呈現(xiàn)的內(nèi)容添履。當(dāng)然,我們最終的目標(biāo)還是要找到目標(biāo)的UI元素脑又,但是我們是通過(guò)其數(shù)據(jù)源來(lái)進(jìn)行入手的暮胧。
尋找數(shù)據(jù)
那么,接下來(lái)问麸,我們就要學(xué)習(xí)如何去尋找我們需要的數(shù)據(jù)了往衷!顯然,要想找到我們需要的數(shù)據(jù)严卖,就需要構(gòu)造一個(gè)onData()所使用的Matcher對(duì)象席舍,而這個(gè)對(duì)象的構(gòu)造和使用實(shí)際上和之前我們所用的針對(duì)于View的Matcher大概雷同。比如哮笆,我們可以指定單一條件:
onData(is(instanceOf(MyObject.class)))
表示我們需要找一個(gè)AdapterView来颤,其數(shù)據(jù)源的類型是MyObject(這是一個(gè)自定義的類)。當(dāng)然了稠肘,我們肯定還是需要更加精確地去尋找一個(gè)AdapterView中的指定條目福铅,于是我們可以采用allOf()來(lái)構(gòu)造一個(gè)符合匹配條件:
onData(allOf(is(instanceOf(MyObject.class)), myCustomMatcher()))
如上代碼便使用allOf()方法構(gòu)造了一個(gè)符合匹配規(guī)則。而上面的myCustomMatcher()方法構(gòu)造了一個(gè)自定義的Matcher项阴,我們可以采用自己的自定義Matcher來(lái)更加精準(zhǔn)地進(jìn)行數(shù)據(jù)的匹配滑黔。
//TODO