Android自動(dòng)測(cè)試框架Espresso

不錯(cuò)的官方文檔翻譯(含作者見(jiàn)解)
這篇文章翻譯簡(jiǎn)直太棒了碳胳,本文的內(nèi)容都來(lái)自對(duì)該文章所記錄的筆記。
Android自動(dòng)化測(cè)試--Espresso框架使用
Android官網(wǎng),_科學(xué)上網(wǎng)也訪問(wèn)不了跪求原因

如何使用Espresso

  1. 在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

自定義Matcher

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子略荡,更是在濱河造成了極大的恐慌庵佣,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,002評(píng)論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撞芍,死亡現(xiàn)場(chǎng)離奇詭異秧了,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)序无,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門验毡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人帝嗡,你說(shuō)我怎么就攤上這事晶通。” “怎么了哟玷?”我有些...
    開(kāi)封第一講書人閱讀 169,787評(píng)論 0 365
  • 文/不壞的土叔 我叫張陵狮辽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我巢寡,道長(zhǎng)喉脖,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 60,237評(píng)論 1 300
  • 正文 為了忘掉前任抑月,我火速辦了婚禮树叽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘谦絮。我一直安慰自己题诵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,237評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布层皱。 她就那樣靜靜地躺著性锭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叫胖。 梳的紋絲不亂的頭發(fā)上草冈,一...
    開(kāi)封第一講書人閱讀 52,821評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音瓮增,去河邊找鬼疲陕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛钉赁,可吹牛的內(nèi)容都是我干的蹄殃。 我是一名探鬼主播,決...
    沈念sama閱讀 41,236評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼你踩,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼诅岩!你這毒婦竟也來(lái)了讳苦?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 40,196評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤吩谦,失蹤者是張志新(化名)和其女友劉穎鸳谜,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體式廷,經(jīng)...
    沈念sama閱讀 46,716評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咐扭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,794評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了滑废。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蝗肪。...
    茶點(diǎn)故事閱讀 40,928評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蠕趁,靈堂內(nèi)的尸體忽然破棺而出薛闪,到底是詐尸還是另有隱情,我是刑警寧澤俺陋,帶...
    沈念sama閱讀 36,583評(píng)論 5 351
  • 正文 年R本政府宣布豁延,位于F島的核電站,受9級(jí)特大地震影響腊状,放射性物質(zhì)發(fā)生泄漏诱咏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,264評(píng)論 3 336
  • 文/蒙蒙 一缴挖、第九天 我趴在偏房一處隱蔽的房頂上張望胰苏。 院中可真熱鬧,春花似錦醇疼、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,755評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至埃仪,卻和暖如春乙濒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卵蛉。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,869評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工颁股, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人傻丝。 一個(gè)月前我還...
    沈念sama閱讀 49,378評(píng)論 3 379
  • 正文 我出身青樓甘有,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親葡缰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子亏掀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,937評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容