溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

UIAutomator定位Android控件的方法實(shí)踐和建議(Appium姊妹篇)

發(fā)布時(shí)間:2020-08-10 12:57:21 來源:網(wǎng)絡(luò) 閱讀:307 作者:zhukev 欄目:移動(dòng)開發(fā)

在本人之前的一篇文章<<Appium基于安卓的各種FindElement的控件定位方法實(shí)踐和建議>>第二章節(jié)談到Appium可以通過使用UIAutomator的方法去定位Android界面上的控件,當(dāng)時(shí)只是一筆帶過舉了個(gè)例子。如該文給自己的承諾,今天特撰寫此文以描述UIAutomator各種控件定位的方法,以作為前文的姊妹篇互通有無。

1. 背景

為了和前文達(dá)成一致,這次的實(shí)踐對(duì)象同樣也是使用SDK自帶的NotePad應(yīng)用,同樣是嘗試去獲得在NotesList那個(gè)Activity里的Menu Options上面的那個(gè)Add note菜單選項(xiàng)。以下是UIAutomatorViewer對(duì)界面的一個(gè)截圖.

UIAutomator定位Android控件的方法實(shí)踐和建議(Appium姊妹篇)

但有一個(gè)例外的地方是下文的”通過偽xpath方法定位控件“章節(jié)實(shí)例需要使用到的是NoteEditor這個(gè)activity里面的Menu options,因?yàn)樾枰菔就ㄟ^子控件獲得父控件然后得到兄弟控件的功能,UIAutomatorViewer截圖如下。

UIAutomator定位Android控件的方法實(shí)踐和建議(Appium姊妹篇)

2. 通過文本信息定位

通過控件的text屬性定位控件應(yīng)該是最常用的一種方法了,畢竟移動(dòng)應(yīng)用的屏幕大小有限,存在text重復(fù)的可能性并不大,就算真的有重復(fù),可以添加其他定位方法來縮寫誤差。

2.1 UISelector.text方法

	        addNote = new UiObject(new UiSelector().text("Add note")); 	        assertEquals(addNote.getText(),"Add note");
該方法通過直接查找當(dāng)前界面上所有的控件來比較每個(gè)控件的text屬性是否如預(yù)期值來定位控件,挺好理解的,所以就沒有必要細(xì)說了。

2.2. UISelector.textContains方法

	        addNote = new UiObject(new UiSelector().textContains("Add")); 	        assertEquals(addNote.getText(),"Add note");
此方法跟以上方法類似,但是不需要輸入控件的全部text信息。

2.3 UISelector.textStartsWith方法

	        addNote = new UiObject(new UiSelector().textStartsWith("Add")); 	        assertEquals(addNote.getText(),"Add note");
顧名思義,通過判斷一個(gè)控件的text的開始是否和預(yù)期的字串相吻合來獲得控件,其實(shí)個(gè)人覺得這個(gè)方法存在的必要性不強(qiáng),因?yàn)樗墓δ芡耆梢杂蒙厦娴姆椒ɑ蛘呦旅娴恼齽t表達(dá)式的方法取代。況且既然你提供了textStartsWith方法,為什么你不提供個(gè)textEndWith的方法呢!

2.4 UISelector.textMatches方法

	        addNote = new UiObject(new UiSelector().textMatches("^Add.*")); 	        assertEquals(addNote.getText(),"Add note");
這個(gè)方法是通過正則表達(dá)式的方式來比較控件的text來定位控件,這里有意思的是用戶使用的正則表達(dá)式是有限制的,請(qǐng)看該方法的官方描述:”Set the search criteria to match the visible text displayed for a widget (for example, the text label to launch an app). The text for the widget must match exactly with the string in your input argument“。第一句我們不用管它,關(guān)鍵是第二句,翻譯過來就是”目標(biāo)控件的text(的所有內(nèi)容)必須和我們輸入的正則表達(dá)式完全匹配“。什么意思呢?意思就是你不能像往常的正則表達(dá)式那樣通過比較text的部分吻合來獲得控件。以下面代碼為例子:
	        addNote = new UiObject(new UiSelector().textMatches("^Add")); 	        assertEquals(addNote.getText(),"Add note");
正常來說這個(gè)正則表達(dá)式是沒有問題的,它的意思就是想要“獲取以Add開頭的text的控件,至于Add字串口面是什么值,沒有必要去管它”。但是按照我們上面的官方描述,這樣子是不行的,你必須要把正則表達(dá)式補(bǔ)充完整以使得正而表達(dá)式和控件的text完全進(jìn)行匹配,至于你用什么通配符或者字串就完全按照正則表達(dá)式的語法了。
注意這個(gè)限制在UISlector使用所有的正則表達(dá)式相關(guān)的方法中都有效哦。

3 通過控件的ClassName定位

通過這種方法定位控件存在的一個(gè)問題是很容易發(fā)生重復(fù),所以一般都是先用這種方法去narrow down目標(biāo)控件,然后再去添加其他如text判斷等條件進(jìn)行控件定位。

3.1 UISelector.className方法

	        addNote = new UiObject(new UiSelector().className("android.widget.TextView").text("Add note")); 	        assertEquals(addNote.getText(),"Add note");
實(shí)例中首先通過ClassName找到所有的TextView控件,然后再在這些TextView控件查找text是”Add note“的控件。

3.2 UISelector.classNameMatches方法

	        addNote = new UiObject(new UiSelector().classNameMatches(".*TextView$")); 	        assertEquals(addNote.getText(),"Add note");
通過正則表達(dá)式判斷className是否和預(yù)期的一致,注意正則表達(dá)式的限制和章節(jié)2.4描述的一致

4. 通過偽xpath方法定位

UISelector類提供了一些方法根據(jù)控件在界面的XML布局中的層級(jí)關(guān)系來進(jìn)行定位,但是UIAutomator又沒有真正的提供類似Appium的findElementWithXpath相關(guān)的方法,所以這里我就稱之為偽xpath方法。
這個(gè)章節(jié)使用到的不再是NotesList那個(gè)activity里面的menu options,而是NoteEditor這個(gè)activity里面的Menu options,里面不止有一個(gè)Menu entry。

4.1 通過UiSelector.fromParent或UiObject.getFromParent方法

這種方法我覺得最有用的情況是測(cè)試代碼當(dāng)前在操作的是同一層級(jí)的一組控件中的某一個(gè)控件,轉(zhuǎn)而又需要操作同一層級(jí)的另外一個(gè)控件的時(shí)候。下面的實(shí)例就是通過save控件的父控件找到其同一層級(jí)的兄弟控件delete。這里分別列出了通過UiObject.getFromParent方法和UiSelector.fromParent方法的實(shí)例,事實(shí)上他們的功能是一樣的。
UiObject.getFromPatrent方法:
	        save =  new UiObject(new UiSelector().text("Save")); 	        assertEquals(save.getText(),"Save"); 	        delete = save.getFromParent(new UiSelector().text("Delete")); 	        assertEquals(delete.getText(),"Delete");
UiSelector.fromParent方法(這個(gè)例子有點(diǎn)迂回笨拙,但為了演示功能就將就著看吧):

	        delete = new UiObject(new UiSelector().text("Save").fromParent(new UiSelector().text("Delete"))); 	        assertEquals(delete.getText(),"Delete");

4.2 通過UiSelector.childSelector或UiObject.getChild方法

這種方法是在已知父控件的時(shí)候如何快速的查找該父控件下面的子控件。
UiObject.getChild方法:
	        UiObject parentView = new UiObject(new UiSelector().className("android.view.View")); 	        save = parentView.getChild(new UiSelector().text("Save")); 	        assertEquals(save.getText(),"Save");
UiSelector.childSelector方法:
	        save = new UiObject(new UiSelector().className("android.view.View").childSelector(new UiSelector().text("Save"))); 	        assertEquals(save.getText(),"Save");

5. 通過控件ID定位

在Android API Level18及其以上的版本增加了一個(gè)Android控件的屬性ResourceId,所以要注意在使用這種方法之前先確保你的目標(biāo)測(cè)試設(shè)備和你的UIAutomoator庫jar包使用的都是API Level 18以上的版本。例如我自己使用的就是本地sdk中版本19的庫:D:\Develops\AndroidSDK\platforms\android-19\uiautomator.jar

5.1 UiSelector.resourceId方法

	        addNote = new UiObject(new UiSelector().resourceId("android:id/title")); 	        assertEquals(addNote.getText(),"Add note");

5.2 UiSelector.resourceIdMatches方法

	        addNote = new UiObject(new UiSelector().resourceIdMatches(".+id/title")); 	        assertEquals(addNote.getText(),"Add note");
注意正則表達(dá)式的限制和章節(jié)2.4描述的一致

6. 通過contentDescription定位

在UiAutomator框架和使用了Uiautomator框架的Appium中,控件的屬性contentDescription一直是強(qiáng)調(diào)開發(fā)人員需要添加進(jìn)去的,因?yàn)?/div>
  • 有些控件使用其他辦法很難或者根本沒有辦法定位
  • 最重要的是給每個(gè)控件的contentDescription設(shè)計(jì)個(gè)唯一值讓我們可以非??焖俚亩ㄎ豢丶?,讓我們足夠敏捷!
以下的實(shí)例并沒有真正跑過的,因?yàn)镹otepad應(yīng)用上面的控件是沒有contentDescription這個(gè)屬性的,但是如果我們假設(shè)Add note這個(gè)控件的contentDescription是“AddNoteMenuDesc”的話,代碼的相應(yīng)寫法應(yīng)該就如下了。

6.1 UiSelector.description方法

	        addNote = new UiObject(new UiSelector().description("AddNoteMenuDesc)); 	        assertEquals(addNote.getText(),"Add note");
</pre><h3>6.2 UiSelector.descriptionContains方法</h3></div><div><pre name="code" class="java">	        addNote = new UiObject(new UiSelector().descriptionContains("AddNote")); 	        assertEquals(addNote.getText(),"Add note");

6.3 UiSelector.descriptionStartWith方法

	        addNote = new UiObject(new UiSelector().descriptionStartsWith("AddNote")); 	        assertEquals(addNote.getText(),"Add note");

6.4 UiSelector.descriptionMatches方法

	        //addNote = new UiObject(new UiSelector().descriptionMatches("^AddNote.*$")); 	        //assertEquals(addNote.getText(),"Add note");

7.通過其他方法定位

除了以上比較常用的方法外,UIAutomator還支持其他一些方法,比如根據(jù)控件屬性是否可點(diǎn)擊可聚焦可長(zhǎng)按等來縮小要定位的控件的范圍,具體使用方法不一一列舉,可以查看以下測(cè)試驗(yàn)證代碼。
package majcit.com.UIAutomatorDemo;  import com.android.uiautomator.core.UiDevice; import com.android.uiautomator.core.UiObject; import com.android.uiautomator.core.UiObjectNotFoundException; import com.android.uiautomator.core.UiScrollable; import com.android.uiautomator.core.UiSelector; import com.android.uiautomator.testrunner.UiAutomatorTestCase;  import static org.hamcrest.Matchers.*; import static org.hamcrest.MatcherAssert.assertThat;  public class UISelectorFindElementTest extends UiAutomatorTestCase { 	 	 public void testDemo() throws UiObjectNotFoundException {   	        UiDevice device = getUiDevice(); 	        device.pressHome();   	        // Start Notepad 	        UiObject appNotes = new UiObject(new UiSelector().text("Notes"));  	        appNotes.click();   	        //Sleep 3 seconds till the app get ready 	        try {   	            Thread.sleep(3000);   	        } catch (InterruptedException e1) {   	            // TODO Auto-generated catch block   	            e1.printStackTrace();   	        }   	         	        //Evoke the system menu option 	        device.pressMenu(); 	        UiObject addNote = new UiObject(new UiSelector().text("Add note")); 	        assertEquals(addNote.getText(),"Add note"); 	         	        addNote = new UiObject (new UiSelector().checked(false).clickable(true)); 	        assertEquals(addNote.getText(),"Add note"); 	         	         	        addNote = new UiObject(new UiSelector().className("android.widget.TextView").text("Add note")); 	        assertEquals(addNote.getText(),"Add note"); 	         	        addNote = new UiObject(new UiSelector().classNameMatches(".*TextView$")); 	        assertEquals(addNote.getText(),"Add note"); 	         	        //addNote = new UiObject(new UiSelector().description("AddNoteMenuDesc)); 	        //assertEquals(addNote.getText(),"Add note"); 	         	        //addNote = new UiObject(new UiSelector().descriptionContains("AddNote")); 	        //assertEquals(addNote.getText(),"Add note"); 	         	        //addNote = new UiObject(new UiSelector().descriptionStartsWith("AddNote")); 	        //assertEquals(addNote.getText(),"Add note"); 	         	        //addNote = new UiObject(new UiSelector().descriptionMatches("^AddNote.*$")); 	        //assertEquals(addNote.getText(),"Add note"); 	         	        addNote = new UiObject(new UiSelector().focusable(true).text("Add note")); 	        assertEquals(addNote.getText(),"Add note"); 	         	        addNote = new UiObject(new UiSelector().focused(false).text("Add note")); 	        assertEquals(addNote.getText(),"Add note"); 	         	         	        //TBD 	        //addNote = new UiObject(new UiSelector().fromParent(selector)) 	         	        addNote = new UiObject(new UiSelector().index(0).text("Add note")); 	        assertEquals(addNote.getText(),"Add note"); 	         	        addNote = new UiObject(new UiSelector().className("android.widget.TextView").enabled(true).instance(0)); 	        assertEquals(addNote.getText(),"Add note"); 	         	        addNote = new UiObject(new UiSelector().longClickable(false).text("Add note")); 	        assertEquals(addNote.getText(),"Add note"); 	         	        addNote = new UiObject(new UiSelector().text("Add note")); 	        assertEquals(addNote.getText(),"Add note"); 	         	        addNote = new UiObject(new UiSelector().textContains("Add")); 	        assertEquals(addNote.getText(),"Add note"); 	         	        addNote = new UiObject(new UiSelector().textStartsWith("Add")); 	        assertEquals(addNote.getText(),"Add note"); 	         	         	        addNote = new UiObject(new UiSelector().textMatches("Add.*")); 	        assertEquals(addNote.getText(),"Add note"); 	         	        addNote = new UiObject(new UiSelector().resourceId("android:id/title")); 	        assertEquals(addNote.getText(),"Add note"); 	         	        addNote = new UiObject(new UiSelector().resourceIdMatches(".+id/title")); 	        assertEquals(addNote.getText(),"Add note"); 	         	        //Go to the editor activity, need to cancel menu options first 	        device.pressMenu(); 	        //Find out the new added note entry 	        UiScrollable noteList = new UiScrollable( new UiSelector().className("android.widget.ListView"));   	        //UiScrollable noteList = new UiScrollable( new UiSelector().scrollable(true));  	        UiObject note = null; 	        if(noteList.exists()) { 	        	note = noteList.getChildByText(new UiSelector().className("android.widget.TextView"), "Note1", true);   	        	//note = noteList.getChildByText(new UiSelector().text("Note1"), "Note1", true);  	        } 	        else { 	        	note = new UiObject(new UiSelector().text("Note1")); 	        } 	        assertNotNull(note); 	         	        //Go to the NoteEditor activity 	        note.click(); 	        device.pressMenu(); 	         	        UiObject save = null; 	        UiObject delete = null; 	         	        save =  new UiObject(new UiSelector().text("Save")); 	        assertEquals(save.getText(),"Save"); 	        delete = save.getFromParent(new UiSelector().text("Delete")); 	        assertEquals(delete.getText(),"Delete"); 	         	        delete = new UiObject(new UiSelector().text("Save").fromParent(new UiSelector().text("Delete"))); 	        assertEquals(delete.getText(),"Delete"); 	         	        save = new UiObject(new UiSelector().className("android.view.View").childSelector(new UiSelector().text("Save"))); 	        assertEquals(save.getText(),"Save"); 	         	        UiObject parentView = new UiObject(new UiSelector().className("android.view.View")); 	        save = parentView.getChild(new UiSelector().text("Save")); 	        assertEquals(save.getText(),"Save"); 	         	         	           	    }    } 

 

作者

自主博客

微信

CSDN

天地會(huì)珠海分舵

http://techgogogo.com


服務(wù)號(hào):TechGoGoGo

掃描碼:

UIAutomator定位Android控件的方法實(shí)踐和建議(Appium姊妹篇)

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI

<noframes id="v6pjb"></noframes>