成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Android自動(dòng)化測試-從入門到入門(5)AdapterView的測試

hqman / 697人閱讀

摘要:在答疑君的老師頁面,有一個(gè)老師搜索的功能。實(shí)際上,雖然方法是針對(duì)來進(jìn)行測試的,但是在答疑君的測試腳本中,有時(shí)針對(duì)我也會(huì)采用方法直接去進(jìn)行匹配,因?yàn)橛行┖唵蔚膱鼍捌鋵?shí)是不需要那么復(fù)雜的數(shù)據(jù)分析的,只關(guān)注于上的顯示我也能夠找到中的某個(gè)控件。

在之前的文章中,我們簡單介紹了Espresso的使用。通過onView()方法我們可以快速定位到界面上我們需要測試的目標(biāo)元素。整體來說,onView()比較適用于UI比較簡單的情況,在不需要過于復(fù)雜的匹配條件的情況下是很方便的。但是,對(duì)于類似ListView這種有UI復(fù)用的元素來說,只是通過onView()就顯得復(fù)雜了一點(diǎn),我們來看一下針對(duì)這種情況應(yīng)有何種方案。

AdapterView

AdapterView是一種通過Adapter來動(dòng)態(tài)加載數(shù)據(jù)的界面元素。我們常用的ListView, GridView, Spinner等等都屬于AdapterView。不同于我們之前提到的靜態(tài)的控件,AdapterView在加載數(shù)據(jù)時(shí),可能只有一部分顯示在了屏幕上,對(duì)于沒有顯示在屏幕上的那部分?jǐn)?shù)據(jù),我們通過onView()是沒有辦法找到的。

對(duì)于AdapterView,Espresso提供了如下方法用來查找元素:

/**
 * 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 dataMatcher) {}

我們首先來研究一下這個(gè)方法的返回值。從以上定義可以看出,該方法返回了一個(gè)DataInteraction對(duì)象,還記得onView()方法返回的ViewInteraction對(duì)象么?這兩者的區(qū)別可以大概描述為:

ViewInteraction: 關(guān)注于已經(jīng)匹配到的目標(biāo)控件。通過onView()方法我們可以找到符合匹配條件的唯一的目標(biāo)控件,我們只需要針對(duì)這個(gè)控件進(jìn)行我們需要的操作。

DataInteraction: 關(guān)注于AdapterView的數(shù)據(jù)。由于AdapterView的數(shù)據(jù)源可能很長,很多時(shí)候無法一次性將所有數(shù)據(jù)源顯示在屏幕上,因此我們主要先關(guān)注AdapterView中包含的數(shù)據(jù),而非一次性就進(jìn)行View的匹配。

我們?cè)賮硌芯恳幌逻@個(gè)方法的入?yún)?。從以上定義看出,該方法接收了一個(gè)Matcher的參數(shù),該參數(shù)用來指定一個(gè)匹配規(guī)則。還記得onView()的入?yún)⒚矗渴且粋€(gè)Matcher對(duì)象。從類型上來看,這兩者的區(qū)別也不言而喻:

Matcher: 構(gòu)造一個(gè)針對(duì)于View匹配的匹配規(guī)則;

Matcher: 構(gòu)造一個(gè)針對(duì)于Object(數(shù)據(jù))匹配的匹配規(guī)則。

從以上對(duì)比可以看出,我們?cè)谑褂?b>onData()方法對(duì)AdapterView進(jìn)行測試的時(shí)候,我們的思路就轉(zhuǎn)變成了首先關(guān)注這個(gè)AdapterView的具體數(shù)據(jù),而不是UI上呈現(xiàn)的內(nèi)容。當(dāng)然,我們最終的目標(biāo)還是要找到目標(biāo)的UI元素,但是我們是通過其數(shù)據(jù)源來進(jìn)行入手的。

尋找數(shù)據(jù)

那么,接下來,我們就要學(xué)習(xí)如何去尋找我們需要的數(shù)據(jù)了!顯然,要想找到我們需要的數(shù)據(jù),就需要構(gòu)造一個(gè)onData()所使用的Matcher對(duì)象,而這個(gè)對(duì)象的構(gòu)造和使用實(shí)際上和之前我們所用的針對(duì)于ViewMatcher大概雷同。比如,我們可以指定單一條件:

onData(is(instanceOf(MyObject.class)))

表示我們需要找一個(gè)AdapterView,其數(shù)據(jù)源的類型是MyObject(這是一個(gè)自定義的類)。當(dāng)然了,我們肯定還是需要更加精確地去尋找一個(gè)AdapterView中的指定條目,于是我們可以采用allOf()來構(gòu)造一個(gè)符合匹配條件:

onData(allOf(is(instanceOf(MyObject.class)), myCustomMatcher()))

如上代碼便使用allOf()方法構(gòu)造了一個(gè)符合匹配規(guī)則(allOf()方法可以參考第三篇文章Espresso入門里的介紹)。而上面的myCustomMatcher()方法構(gòu)造了一個(gè)自定義的Matcher,我們可以采用自己的自定義Matcher來更加精準(zhǔn)地進(jìn)行數(shù)據(jù)的匹配。

自定義Matcher

接下來我們要感受一下自定義Matcher的強(qiáng)大之處了!為了更好地給大家介紹自定義Matcher,我舉一個(gè)答疑君APP里面的例子來進(jìn)行說明。

在答疑君APP的老師頁面,有一個(gè)老師搜索的功能。當(dāng)我點(diǎn)擊搜索框時(shí),界面上便會(huì)顯示之前的搜索關(guān)鍵字歷史。現(xiàn)在,我需要在這個(gè)搜索關(guān)鍵字列表中點(diǎn)擊相應(yīng)的關(guān)鍵字來觸發(fā)搜索。

簡單來說,我的目的就是:在搜索歷史ListView中點(diǎn)擊搜索關(guān)鍵字為TEXT的條目。

首先,我的ListView的數(shù)據(jù)源類型為List,于是我先構(gòu)造一個(gè)數(shù)據(jù)類型匹配條件:

is(instanceOf(SearchItem.class))

這個(gè)構(gòu)造條件就指定了列表的數(shù)據(jù)源為SearchItem類型。請(qǐng)注意,Espresso在根據(jù)onData()進(jìn)行類型匹配時(shí),是根據(jù)我們的Adapter.getItem()方法返回的數(shù)據(jù)類型進(jìn)行匹配的。如果我們自己實(shí)現(xiàn)了一個(gè)自定義的Adapter,請(qǐng)注意我們構(gòu)造的匹配規(guī)則要和getItem()方法返回的數(shù)據(jù)類型相統(tǒng)一。

接下來,我就需要去找那個(gè)含有TEXT關(guān)鍵字的數(shù)據(jù)項(xiàng)了。我的SearchItem類的定義極其簡單:

public class SearchItem {
    private String keyword;
    
    public SearchItem() {}
    
    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }
    
    public String getKeyword() {
        return keyword;
    }
}

接下來我只要找到那個(gè)keywordTEXTSearchItem數(shù)據(jù)項(xiàng)就可以了。為此,我構(gòu)造了如下的一個(gè)自定義Matcher:

/**
 * 查找指定關(guān)鍵字的搜索條件
 * @param name 需要搜索的關(guān)鍵字
 */
public static Matcher teacherSearchItemWithName(final String name) {
    return new BoundedMatcher(SearchItem.class) {
        @Override
        protected boolean matchesSafely(SearchItem item) {
            return item != null
                    && !TextUtils.isEmpty(item.getKeyword())
                    && item.getKeyword().equals(name);
        }

        @Override
        public void describeTo(Description description) {
            description.appendText("SearchItem has Name: " + name);
        }
    };
}

接下來對(duì)該方法做一些說明,以助于幫助大家構(gòu)造自己的Matcher:

1. @return Matcher

很顯然,返回值必須是一個(gè)Matcher對(duì)象,代表一個(gè)針對(duì)于Object數(shù)據(jù)的匹配規(guī)則。這也是onData()方法入?yún)⒌囊蟆?/p>

2. BoundedMatcher

以上方法實(shí)際上是構(gòu)造了一個(gè)BoundedMatcher,我們先來看一下BoundedMatcher的定義:

/**
 * Some matcher sugar that lets you create a matcher for a given type
 * but only process items of a specific subtype of that matcher.
 *
 * @param  The desired type of the Matcher.
 * @param  the subtype of T that your matcher applies safely to.
 */
public abstract class BoundedMatcher extends BaseMatcher {
    // ...
    protected abstract boolean matchesSafely(S item);
    // ...
}

由以上定義我們可以看到,BoundedMatcher為我們指定了一個(gè)針對(duì)目標(biāo)類型的子類型進(jìn)行匹配的匹配規(guī)則。比如,我們現(xiàn)在需要一個(gè)Matcher>對(duì)象,但實(shí)際上我們需要考察的目標(biāo)類型是SearchItem,而SearchItem又是Object的子類,因此,我們可以通過BoundedMatcher來構(gòu)造這個(gè)Matcher對(duì)象,只不過我們實(shí)際上進(jìn)行檢查的轉(zhuǎn)變成了SearchItem類型,只要采用如下寫法:

return new BoundedMatcher(SearchItem.class) {...}

3. matchesSafely()

上述復(fù)寫的matchesSafely()方法便是真正執(zhí)行匹配的地方了!大家可以看到,我由BoundedMatcher指定了SearchItem類型,因此matchesSafely()方法也接收了SearchItem類型的入?yún)?,我們只要去考察入?yún)⑻峁┑倪@個(gè)SearchItem對(duì)象是否符合我們的匹配條件即可:

return item != null
       && !TextUtils.isEmpty(item.getKeyword())
       && item.getKeyword().equals(name);

在如上代碼中,我做了三步檢查:

指定SearchItem本身不為null;

指定SearchItemkeyword不為空;

指定SearchItemkeyword和我們需要匹配的name相同。

只有符合這三個(gè)條件,我們才會(huì)認(rèn)為當(dāng)前的SearchItem數(shù)據(jù)項(xiàng)符合我們的預(yù)期。

綜合以上,將之前的兩個(gè)Matcher復(fù)合一下,我便可以構(gòu)造如下的符合匹配規(guī)則了:

onData(allOf(is(instanceOf(SearchItem.class)), teacherSearchItemWithName(TEXT)))

這樣一來,我就能夠成功地在我的搜索歷史列表中找到關(guān)鍵字為TEXT的數(shù)據(jù)項(xiàng)了。

指定AdapterView

這樣就完了嘛?是的,針對(duì)自定義Matcher就已經(jīng)講完了。實(shí)際上我在運(yùn)行以上腳本的時(shí)候,Espresso還是給我報(bào)了個(gè)AmbiguousViewMatcherException的異常。這是因?yàn)椋鹨删鼳PP的布局比較復(fù)雜,在當(dāng)前的View Hierarchy中有好幾個(gè)AdapterView,我需要指定我要進(jìn)行匹配的AdapterView到底是哪一個(gè)。

Espresso提供了如下方法來完成這件事情:

/**
 * Selects a particular adapter view to operate on, by default we operate on any adapter view
 * on the screen.
 */
public DataInteraction inAdapterView(Matcher adapterMatcher){}

inAdapterView()可以讓我們指定我們需要匹配哪個(gè)AdapterView。我的搜索歷史列表的id為teacher_page_search_history_list,因此,我只要在上面的基礎(chǔ)上增加如下一行:

onData(allOf(is(instanceOf(SearchItem.class)), teacherSearchItemWithName(TEXT)))
.inAdapterView(withId(R.id.teacher_page_search_history_list))

便解決了問題。現(xiàn)在,Espresso只會(huì)針對(duì)我的搜索歷史列表進(jìn)行數(shù)據(jù)匹配了!

關(guān)于如何抉擇

到目前為止,我們介紹了onView()onData()的使用。從以上的文章中,相信大家也能夠感受到這兩種匹配思路的設(shè)計(jì)目的與區(qū)別。在我們平時(shí)的測試腳本編寫的過程中,我個(gè)人還是建議,一切都要按照我們自己的實(shí)際情況來進(jìn)行方法的選擇。

實(shí)際上,雖然onData()方法是針對(duì)AdapterView來進(jìn)行測試的,但是在答疑君的測試腳本中,有時(shí)針對(duì)AdapterView我也會(huì)采用onView()方法直接去進(jìn)行匹配,因?yàn)橛行┖唵蔚膱鼍捌鋵?shí)是不需要那么復(fù)雜的數(shù)據(jù)分析的,只關(guān)注于UI上的顯示我也能夠找到ListView中的某個(gè)控件。話說回來,Espresso只是一個(gè)工具,至于具體如何去用,就看我們自己的發(fā)揮啦!

附錄

Android自動(dòng)化測試-從入門到入門(1) Hello Testing!
Android自動(dòng)化測試-從入門到入門(2) Testing APIs
Android自動(dòng)化測試-從入門到入門(3) Espresso入門
Android自動(dòng)化測試-從入門到入門(4) uiautomatorviewer
Android自動(dòng)化測試-從入門到入門(5) AdapterView的測試
Android自動(dòng)化測試-從入門到入門(6) 會(huì)玩的Espresso
Android自動(dòng)化測試-從入門到入門(7) UI Automator

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/65420.html

相關(guān)文章

  • Android動(dòng)化測試-入門入門(6)會(huì)玩Espresso

    摘要:附錄自動(dòng)化測試從入門到入門自動(dòng)化測試從入門到入門自動(dòng)化測試從入門到入門入門自動(dòng)化測試從入門到入門自動(dòng)化測試從入門到入門的測試自動(dòng)化測試從入門到入門會(huì)玩的自動(dòng)化測試從入門到入門 之前的文章中,我們介紹了Android自動(dòng)化測試的一些背景,以及Espresso的基本應(yīng)用。除了之前介紹過的Espresso的相關(guān)用法,Espresso還提供了一些其他的用法,可以讓我們?cè)诓煌瑘鼍跋蚂`活使用。這篇...

    Aklman 評(píng)論0 收藏0
  • Android動(dòng)化測試-入門入門(4)uiautomatorviewer

    摘要:右下角部分顯示當(dāng)前選中控件的各個(gè)屬性。然后,向這個(gè)中輸入賬號(hào)信息就完成了一個(gè)表單的輸入。我們可以根據(jù)屬性區(qū)域顯示的來進(jìn)行匹配賬號(hào)小總結(jié)所提供的界面簡單,使用方便,對(duì)于我們的自動(dòng)化測試來說是一個(gè)很好的輔助工具。 我們用如下一行代碼來回顧一下之前介紹過的內(nèi)容: import static android.support.test.espresso.Espresso.onView; impo...

    winterdawn 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

hqman

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<