Robotium之Android控件定位實踐和建議(Appium/UIAutomator姊妹篇)
本人之前曾經撰文描述Appium和UIAutomator框架是如何定位Android界面上的控件的。
- UIAutomator定位Android控件的方法實踐和建議
- Appium基于安卓的各種FindElement的控件定位方法實踐和建議
今天我們換一個淵源更留長,當今更盛行的框架Robotium,實踐下看它又是如何對控件進行定位的。
1. 背景
為保持這個系列的一致性,我們繼續用SDK自帶的NotePad實例應用作為我們的試驗目標應用,但是這次不僅僅是像以前一樣主要圍繞Menu Option里面的那個"Add note”控件進行定位,而是會設計到NotePad上的多個不同的控件定位。但主要圍繞的還是Notepad的NotesList這個Launchable activity了,下面先看下UIAutomatorViewer下面捕獲的我們會涉及到的不同界面吧。
- NotesList Activity的第一個頁面列表中會包含note3到note9的筆記
- NoteList Activity往下拉后還會看到有note1到note2以及兩個重復的名稱為note的筆記
- 點擊系統的menu后會出現“Add note”這個menu entry供我們測試驗證用
2. 通過控件的文本信息text進行定位
Robotium里面的很多方法都支持直接輸入text作為參數進行操作,比如clickOnText,clickLongOnText等,通過text來查找控件是最快捷顯而易見的。
以下我們用clickOnText以及其重載方法進行說明,其他的以text方式查找的方法類似(我們當然也可以直接調用Solo.clickOnButton(String text)來限制只通過text方法來查找button控件了)。
2.1Solo.clickOnText(String text)
2.1.1 示例
solo.clickOnText("^note$"); assertTrue(solo.searchText("^note$"));
找到第一個text
絕對等于note的控件并進行點擊。
2.1.2 分析和建議
以上示例有兩點需要指出來引起注意的:
- Robotium會自動往下滾動直到定位到目標控件為止:這就是為什么以上示例不用先進行scrolldown動作就可以直接查找到在第二個頁面的“note”的原因
- Robotium如果查找到的滿足條件的控件多于一個的話,默認會返回第一個
- Robotium根據text進行控件定位的時候默認就是支持用正則表達式的
比如把以上例子改成下面就會斷言失敗:
solo.clickOnText("note"); assertTrue(solo.searchText("^note$"));
在這里點擊的將會列表最上面的日記,在我們的例子中就是“note9”。為什么呢?因為note1到note9以及note都包含了“note”這個text,而以上代碼中的參數在正則表達式中的意思是“
查找文本中包含note字串的控件進行點擊”。所以我們必須把它改成"^note$"以精確查找text絕對等于note的控件。
那么如果這樣子還是有重復的控件怎么辦呢?請往下看。
2.2 Solo.clickOnText(String text, int match)
2.2.1 示例
solo.clickOnText("^note$", 2); assertTrue(solo.searchText("^note$"));
2.2.2 解析
如果通過text查找回來的控件有超過一個,那么我們可以在基于1的基礎上從左到右自上往下的順序指定需要的是第幾個控件。
2.3 Solo.clickOnText(String text, int match, boolean scroll)
2.3.1 示例
solo.clickOnText("^note2$", 1, false); assertTrue(solo.searchText("^note2$"));
2.3.2 解析
最后一個參數是指定是否自動scrolldown去查找控件。
3. ListView子控件定位
如果要定位的控件是在一個ListView里面的,那么除了可以使用以上的text方式進行定位之外,我們還可以通過指定控件在該ListView的地幾行進行定位。
3.1Solo.clickInList(int line):指定行數進行定位
3.1.1 示例
solo.clickInList(2); assertTrue(solo.searchText("^note8$"));
3.1.2 解析
點擊第一個ListView的第2行。那么如果界面有多于一個ListView怎么辦呢?那么就要看下面這個方法了。
3.2 Solo.clickInList(int line, int index):同時指定第幾個ListView的第幾行進行定位
3.2.1 示例
solo.clickInList(2, 0); assertTrue(solo.searchText("^note8$"));
3.2.2 解析
其中第一個參數是行數,第二個參數指的是第幾個ListView,按照我的經驗,就是基于1,界面從左到右從上到下的順序這個ListView所處的位置。
4. ActionBar控件定位
Android 3.0之后引入的新的對象,ActionBar可以說是一個方便快捷的導航神器。它可以作為活動的標題,突出活動的一些關鍵操作(如“搜索”、“創建”、“共享”等)、作為菜單的靈活使用,還可以實現類似TabWidget的標簽功能以及下拉導航的功能,系統能夠很好根據不同的屏幕配置來適應ActionBar的外觀。因為在NotePad中沒有實現ActionBar功能,所以我們這章節使用的是小米自帶的便簽進行描述說明。
4.1 Solo.clickOnActionBarHomeButton()
該方法的目的就是點擊ActionBar左上角的Home或者Up的icon導航到上一頁
4.2 Solo.clickOnActionBarItem(int id)
參數整型id指的是R.id,也就是說項目工程中的R.java里面的id。
5. 通過控件的排列順序來定位
在上面的3.2.2章節我們已經體驗過如何通過指定第幾個ListView來定位控件了。事實上很多控件都可以通過指定控件在界面上的排列順序來定位,就以click相關的方法為例子,我們就可以找出以下這些針對不同控件的排列順序來定位的方法
- Solo.clickOnButton(int index)
- Solo.clickOnCheckBox(int index);
- Solo.clickOnEditText(int index)
- Solo.clickOnImage(int index)
- Solo.clickOnImageButton(int index)
- Solo.clickOnRadioButton(int index)
這種定位方式如同MonkeyRunner通過坐標點進行定位的方式一樣存在局限性,很大一個就是當界面控件順序有調整的時候就要立刻進行測試代碼的維護更新。
5.1 示例
solo.clickLongOnTextAndPress("note9", 2); solo.clickOnButton(0);
5.2 分析
以上代碼所做的事情就是
- 在彈出menu中選擇由0數起的第2個menu entry,也就是“Edit Title”
- 點擊界面從左到右由上往下由0數起的第0個Button,也就是“ok“這個Button
6. 通過控件的內部屬性來定位
以上獲取控件的方式和操作該控件都是在一個方法中就實現了的,其實Robotium也支持先獲得控件,然后再針對控件慢慢進行操作了。
Robotium的Solo類中有一些列getView的重載方法就是專門做這個事情的。但是不像UIAutoamtor和Appium支持用眾多的控件內部屬性判斷是否是目標控件,Robotium只支持通過兩種控件內部屬性來定位控件:
- ResrouceId:可以是字符串類型(通過UIAutomatorViewer獲得)也可以是整型(通過R.java文件獲得)
- ClassName:控件的Class(可以通過UIAutomatorViewer獲得),不過注意不是字符串,而是真實的class
這里我們用getView來作為一個例子來說明如何通過控件內部屬性獲得控件,以起到一個拋磚引玉的左右。當然除了getView,Robotium還支持其他的入getViews,getCurrentViews等方法,但原理一致,就不累述了。
6.1 Solo.getView(String/int id,[int index])
6.1.1 示例
View view = null; view = solo.getView("android:id/text1",1); solo.clickOnView(view);
6.1.2 分析
這段代碼所做的事情就是去獲得從0數起的第1個ResourceId為”android:id/text1"的控件。
這里為什么需要填寫index呢?其實我們要注意Android的Activity下面的控件的ResourceId是允許重復的,比如NotePad上面的ListView里面的每一個Note的ResourceId其實都是"android:id/text1".所以這種情況下我們必須要加上index來區分開我們需要的是第幾個note。
比如以下代碼得到的將是ListView里面的第一個Note
View view = null; view = solo.getView("android:id/text1"); solo.clickOnView(view);
6.2 Solo.getView(Class<T> viewClass, int index)
6.2.1 示例
View view = null; view = solo.getView(TextView.class,1); solo.clickOnView(view);
點擊從0開始的第1個TextView類型的控件,也就是下圖中的note4。按照從左到右自上往下的順序,<span style="font-family: Arial, Helvetica, sans-serif;">這里的第0個是ListView的Title名稱為Notes的 那個TextView:</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><img src="http://img.blog.csdn.net/20141004182018767?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh2YmFpdGlhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /> </span>
6.2.2 解析
注意這里的類名viewClass和UIAutomator(New UiSelector().className(String className))以及Appium(AppiumDriver.findElementByClassName(String className))的通過className查找時填寫的類的格式和類型是不一樣的,就以TextView為例:
- Robotium :Class類型 || 不需要FQCN(也就是不需要寫成andoid.widget.Textview,這在UIAutomator和Appium中是必須的)
- UIAutomator: String類型 || FQCN
- Appium :String類型 || FQCN
7 無需定位的控件
我們常用到的兩個系統控件是不需要定位的,一個是系統的Menu鍵,一個是系統的goBack。但是注意Menu下面的Menu Entry還是需要定位的,比如我們例子中的”Add note“這個Menu Entry。
8 還有嗎?
以上列出了Robotium中對本人當前最重要的獲取控件的方法,當然Solo里面還有一些其他的方法,但不是容易理解就是現在用不上,所以就不一一陳述了
- 通過坐標點操作控件 :容易理解,就是獲得坐標點然后點擊屏幕坐標。
- 獲取和操作WebView控件 :現在用不上,到時有用到了再去深究
- 還有其他嗎?