前言
相信大家在使用 Appium 时,都会遇到过一个问题,怎么更好地在一个页面中对某一个元素进行更快速的定位方式。本篇文章基于大家刚接触 Appium,对元素定位还是比较模糊。
Appium 定位方式是依赖于 Selenium 的。所以 Selenium 的定位方式,Appium 都支持,还加上Android 和 iOS 原生的定位方式。这样一下来,就有十多种定位方式,挑选哪一种使用,也是有些讲究的。
1. Appium 定位方式种类
目前,Appium 支持的定位方式,如下所示:
cssSelector # Selenium 最强大的定位方法,比 xpath 速度快,但比 xpath 难上手
linkText # 链接元素的全部显示文字
partialLinkText # 链接元素的部分显示文字
name # 元素的 name 属性,目前官方在移动端去掉这个定位方式,使用 AccessibilityId 替代
tagName # 元素的标签名
className # 元素的 class 属性
id # 元素的 id 属性
xpath # 比 css 定位方式稍弱一些的定位方法,但胜在容易上手,比较好使用,缺点就是速度慢一些。
AccessibilityId # Appium 中用于替代 name 定位方式
AndroidUIAutomator # Android 测试,最强大速度最快的定位方式
iOSnspredicateString # iOS 谓词的定位方式,仅支持 XCTest 框架,需大于 iOS 9.3或以上
IosUIAutomation # iOS 谓词的定位方式,仅支持 UIAutomation 框架,需大于 iOS 9.3或以下
iOSClassChain # 国外大神 Mykola Mokhnach 开发类似 xpath 的定位方式,仅支持 XCTest 框架,,不如 xpath 和 iOSnspredicateString 好
windowsAutomation # windows 应用自动化的定位方式
上述所示的定位方式中,name
由于官方的原因废弃掉,所以不在这里赘述了。tagName
、linkText
和 partialLinkText
在我的理解中,一般是在 web 页面使用,移动端很少用。
接下来,说一下我认为在 App UI自动化中常用到定位方式的详细用法。
1.1 className
使用元素的className
属性定位,支持:Android 和 iOS,推荐使用。
MobileBy.className("XCUIElementTypeButton")
1.2 id
使用元素的resource-id
属性定位,支持:Android,仅支持 Android 4.2或以上,推荐使用,一般来说,使用 id 能准确定位,就使用 id 吧,定位信息简洁,不容易错误。反正我没有在 iOS 用过,大家有正确使用过的例子,可以分享一下。
MobileBy.id("package.name:id/android")
1.3 xpath
支持:Android 和 iOS。但由于 iOS 10开始使用的 XCUITest 框架原声不支持,定位速度很慢,所以官方现在不推荐大家使用,也有其他替代的定位方式可使用。
-
MobileBy.xpath("className/className/className/className")
-
使用相对路径定位
MobileBy.xpath("//className")
-
通过元素的索引定位
MobileBy.xpath("//className[index]")
-
通过元素的属性定位
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("更多信息")
1.5 AndroidUIAutomator
仅支持 Android 4.2或以上,可支持元素的单个属性和多个属性定位,推荐使用。
index(int index)
text(String text)
resourceId(String id)
className(String className)
packageName(String packageName)
description(String desc)
checked(boolean val)
clickable(boolean val)
enabled(boolean val)
longClickable(boolean val)
selected(boolean val)
instance(int val)
# 其他一些详细方法(包括正则表达式匹配),请查看 Android 源码中,UiSelector 类定义的方法
例子:
MobileBy.AndroidUIAutomator("new UiSelector().text(\"发送\")") # 使用一种属性定位
MobileBy.AndroidUIAutomator("new UiSelector().text(\"发送\").clickable(true)") # 使用两种属性定位
1.6 iOSnspredicate
仅支持 iOS 10或以上,可支持元素的单个属性和多个属性定位,推荐使用。详细请参照
iOSNsPredicate 定位。
MobileBy.iOSnspredicateString("type == 'XCUIElementTypeButton'") # 使用一种属性定位
MobileBy.iOSnspredicateString("type == 'XCUIElementTypeButton' AND label == '更多信息'") # 使用两种属性定位
具体 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]')
1.8 IosUIAutomation
仅支持 iOS 9.3或以下,是 iOS 旧框架 UIAutomation 的定位方式,这个定位类型同样可使用 iOS 谓词进行定位,详细可参考:iOSnspredicate
MobileBy.IosUIAutomation("type == 'UIAButton'") # 使用一种属性定位
MobileBy.IosUIAutomation("type == 'UIAButton' AND label == '更多信息'") # 使用两种属性定位
2. 元素复杂定位
在贝聊家长版 Android 的登录页面中,手机号码输入框和密码输入框两个元素信息如下图所示。


手机号码输入框和密码输入框大部分属性都一致,单独使用 className 和 id 已经不可行了。可能有同学问,输入框不是有默认文案(text 属性)吗?使用text 属性定位就可以啦。
在初始登录时,使用这个text 属性定位的确可以,但如果不是初始登录,手机号码输入框残留上次登录的手机号码,text 属性就变成上次登录的手机号,如 图3 所示。

在类似这样的输入框中,元素的 text 属性会不断变化。在进行元素定位时,我们会尽可能避免使用可变化值的属性进行定位。
由此可见,手机号码、密码两个输入框基本上不能使用单一属性进行定位,如果这样的话,我们可以使用元素多属性进行定位。观察图1和图2,两个元素的属性大部分一致,但还是有3个属性是不同的:focused、password、instance。再结合只有两个输入框相同的属性值,这样一定位,即可找到该元素了。
使用 AndroidUIAutomator 定位。UiSelector 不支持 password 属性定位。
# 手机号码输入框
MobileBy.AndroidUIAutomator("new UiSelector().resourceId(\"com.babychat:id/edit_content\").focused(true)")
MobileBy.AndroidUIAutomator("new UiSelector().className(\"android.widget.EditText\").instance(0)")
# 密码输入框
MobileBy.AndroidUIAutomator("new UiSelector().resourceId(\"com.babychat:id/edit_content\").focused(false)")
MobileBy.AndroidUIAutomator("new UiSelector().className(\"android.widget.EditText\").instance(1)")
使用 xpath 定位,不支持使用 instance 属性定位
# 手机号码输入框
MobileBy.xpath("//android.widget.EditText[@focused='true']")
MobileBy.xpath("//android.widget.EditText[@password='false']")
# 密码输入框
MobileBy.xpath("//android.widget.EditText[@focused='false']")
MobileBy.xpath("//android.widget.EditText[@password='true']")
3. 总结
Appium 元素的一些定位方式,大体上就上面跟大家所说的那样。只要能将你想要的元素定位到,具体使用哪个,就得看个人习惯了。但如果想要定位的元素,其属性与其他元素相似较多的话,就需要使用两种甚至三种属性进行定位了,具体使用哪些属性,就得跟其他属性一一对比,找出不相同的属性,根据属性来使用定位类型,这样比较靠谱一些。
本篇文章是本人在学习 Appium 中所得到的感悟,如果大家有更好的方法,也可以说出来,大家一起讨论,一起进步!
作者:DC_ing
链接:https://www.jianshu.com/p/9f842862f883
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。