標籤:

[貝聊科技]Appium 元素定位方式大揭秘

前言

相信大家在使用 Appium 時,都會遇到過一個問題,怎麼更好地在一個頁面中對某一個元素進行更快速的定位方式。本篇文章基於大家剛接觸 Appium,對元素定位還是比較模糊。

Appium 定位方式是依賴於 Selenium 的。所以 Selenium 的定位方式,Appium 都支持,還加上Android 和 iOS 原生的定位方式。這樣一下來,就有十多種定位方式,挑選哪一種使用,也是有些講究的。

1. Appium 定位方式種類

目前,Appium 支持的定位方式,如下所示:

cssSelector # Selenium 最強大的定位方法 xpath 速度快但比 xpath 難上手nlinkText # 鏈接元素的全部顯示文字npartialLinkText # 鏈接元素的部分顯示文字nname # 元素的 name 屬性目前官方在移動端去掉這個定位方式使用 AccessibilityId 替代ntagName # 元素的標籤名nclassName # 元素的 class 屬性nid # 元素的 id 屬性nxpath # css 定位方式稍弱一些的定位方法但勝在容易上手比較好使用缺點就是速度慢一些nAccessibilityId # Appium 中用於替代 name 定位方式nAndroidUIAutomator # Android 測試最強大速度最快的定位方式niOSNsPredicateString # iOS 謂詞的定位方式僅支持 XCTest 框架需大於 iOS 9.3或以上nIosUIAutomation # iOS 謂詞的定位方式僅支持 UIAutomation 框架需大於 iOS 9.3或以下niOSClassChain # 國外大神 Mykola Mokhnach 開發類似 xpath 的定位方式僅支持 XCTest 框架,,不如 xpath iOSNsPredicateString nwindowsAutomation # windows 應用自動化的定位方式n

上述所示的定位方式中,name由於官方的原因廢棄掉,所以不在這裡贅述了。tagName、linkText 和 partialLinkText 在我的理解中,一般是在 web 頁面使用,移動端很少用。

接下來,說一下我認為在 App UI自動化中常用到定位方式的詳細用法。

1.1 className

使用元素的className屬性定位,支持:Android 和 iOS,推薦使用。

MobileBy.className("XCUIElementTypeButton")n

1.2 id

使用元素的resource-id屬性定位,支持:Android,僅支持 Android 4.2或以上,推薦使用,一般來說,使用 id 能準確定位,就使用 id 吧,定位信息簡潔,不容易錯誤。反正我沒有在 iOS 用過,大家有正確使用過的例子,可以分享一下。

MobileBy.id("package.name:id/android")n

1.3 xpath

支持:Android 和 iOS。但由於 iOS 10開始使用的 XCUITest 框架原聲不支持,定位速度很慢,所以官方現在不推薦大家使用,也有其他替代的定位方式可使用。

1. 使用絕對路徑定位,如截圖所顯示的 xpath 路徑

MobileBy.xpath("className/className/className/className")

2. 使用相對路徑定位

MobileBy.xpath("//className")

3. 通過元素的索引定位

MobileBy.xpath("//className[index]")

4. 通過元素的屬性定位

MobileBy.xpath("//className[@label=更多信息]") # 使用一種屬性定位

MobileBy.xpath("//className[@label=更多信息][@isVisible=1]") # 使用兩種屬性定位

MobileBy.xpath("//className[contains(@label,更多)]") # 使用部分屬性定位(最強大)

1.4 AccessibilityId

替代以前的name定位方式,推薦使用。

在 Android 上,主要使用元素的content-desc屬性,如該屬性為空,不能使用此定位方式。

在 iOS 上,主要使用元素的label或name(兩個屬性的值都一樣)屬性進行定位,如該屬性為空,如該屬性為空,也是不能使用該屬性。

MobileBy.AccessibilityId("更多信息")n

1.5 AndroidUIAutomator

僅支持 Android 4.2或以上,可支持元素的單個屬性和多個屬性定位,推薦使用。

支持元素以下屬性定位:

index(int index)ntext(String text)nresourceId(String id)nclassName(String className)npackageName(String packageName)ndescription(String desc)nchecked(boolean val)nclickable(boolean val)nenabled(boolean val)nlongClickable(boolean val)npassword(boolean val)nselected(boolean val)ninstance(int val)n# 其他一些詳細方法(包括正則表達式匹配),請查看 Android 源碼中,UiSelector 類定義的方法n

例子:

MobileBy.AndroidUIAutomator("new UiSelector().text("發送")") # 使用一種屬性定位nMobileBy.AndroidUIAutomator("new UiSelector().text("發送").clickable(true)") # 使用兩種屬性定位n

元素的所有屬性都可用做定位,功能非常強大,且速度很快。

1.6 iOSNsPredicate

僅支持 iOS 10或以上,可支持元素的單個屬性和多個屬性定位,推薦使用。詳細請參照

iOSNsPredicate 定位。

MobileBy.iOSNsPredicateString("type == XCUIElementTypeButton") # 使用一種屬性定位nMobileBy.iOSNsPredicateString("type == XCUIElementTypeButton AND label == 更多信息") # 使用兩種屬性定位n

具體 iOSNsPredicate 語法結構可查看官方文檔,或查看我另外的一個帖子。

1.7 iOSClassChain

僅支持 iOS 10或以上,這是 github 的 Mykola Mokhnach 大神開發,僅限在 WebDriverAgent 框架使用,用於替代 xpath 的,但使用一陣子後,感覺靈活性沒有 xpath 和 iOSNsPredicate 好,應該還不完善吧。具體使用方法,請見:iOSClassChain。

MobileBy.iOSClassChain(XCUIElementTypeWindow[1]/XCUIElementTypeOther[1]/XCUIElementTypeOther[1]/XCUIElementTypeNavigationBar[1]/XCUIElementTypeOther[1]/XCUIElementTypeButton[2])n

1.8 IosUIAutomation

僅支持 iOS 9.3或以下,是 iOS 舊框架 UIAutomation 的定位方式,這個定位類型同樣可使用 iOS 謂詞進行定位,詳細可參考:iOSNsPredicate

MobileBy.IosUIAutomation("type == UIAButton") # 使用一種屬性定位nnMobileBy.IosUIAutomation("type == UIAButton AND label == 更多信息") # 使用兩種屬性定位n

2. 元素複雜定位

在貝聊家長版 Android 的登錄頁面中,手機號碼輸入框和密碼輸入框兩個元素信息如下圖所示。

圖1

圖2

手機號碼輸入框和密碼輸入框大部分屬性都一致,單獨使用 className 和 id 已經不可行了。可能有同學問,輸入框不是有默認文案(text 屬性)嗎?使用text 屬性定位就可以啦。

在初始登錄時,使用這個text 屬性定位的確可以,但如果不是初始登錄,手機號碼輸入框殘留上次登錄的手機號碼,text 屬性就變成上次登錄的手機號,如 圖3 所示。

圖3

在類似這樣的輸入框中,元素的 text 屬性會不斷變化。在進行元素定位時,我們會儘可能避免使用可變化值的屬性進行定位。

由此可見,手機號碼、密碼兩個輸入框基本上不能使用單一屬性進行定位,如果這樣的話,我們可以使用元素多屬性進行定位。觀察圖1和圖2,兩個元素的屬性大部分一致,但還是有3個屬性是不同的:focused、password、instance。再結合只有兩個輸入框相同的屬性值,這樣一定位,即可找到該元素了。

使用 AndroidUIAutomator 定位。UiSelector 不支持 password 屬性定位。

# 手機號碼輸入框nMobileBy.AndroidUIAutomator("new UiSelector().resourceId("com.babychat:id/edit_content").focused(true)")nMobileBy.AndroidUIAutomator("new UiSelector().className("android.widget.EditText").instance(0)")nn# 密碼輸入框nMobileBy.AndroidUIAutomator("new UiSelector().resourceId("com.babychat:id/edit_content").focused(false)")nMobileBy.AndroidUIAutomator("new UiSelector().className("android.widget.EditText").instance(1)")n

使用 xpath 定位,不支持使用 instance 屬性定位

# 手機號碼輸入框nMobileBy.xpath("//android.widget.EditText[@focused=true]")nMobileBy.xpath("//android.widget.EditText[@password=false]")nn# 密碼輸入框nMobileBy.xpath("//android.widget.EditText[@focused=false]")nMobileBy.xpath("//android.widget.EditText[@password=true]")n

3. 總結

Appium 元素的一些定位方式,大體上就上面跟大家所說的那樣。只要能將你想要的元素定位到,具體使用哪個,就得看個人習慣了。但如果想要定位的元素,其屬性與其他元素相似較多的話,就需要使用兩種甚至三種屬性進行定位了,具體使用哪些屬性,就得跟其他屬性一一對比,找出不相同的屬性,根據屬性來使用定位類型,這樣比較靠譜一些。

本篇文章是本人在學習 Appium 中所得到的感悟,如果大家有更好的方法,也可以說出來,大家一起討論,一起進步!

推薦閱讀:

[從入門到不放棄]多瀏覽器的自動化測試(2)-雲服務測試
Kotlin 來了,對APP測試意味著什麼
性能測試基礎
我也終於用上Powershell了
Android獲取應用大小

TAG:自动化测试 |