Appium Appium-同一个元素不同定位方式的区别

DC · 2017年04月11日 · 最后由 DC 回复于 2018年11月15日 · 5918 次阅读

前言

使用过 Appium 的都知道,元素的定位方式有很多种,具体使用哪一种,主要看业务的需要和自己的使用爱好。下面总结一下,Appium 到底有哪些定位方式,定位的元素以下面截图指定的元素为例子:

这里给 Macaca 的 inspector 查看器打个广告,的确很好用,有需要可到社区的 Macaca 版块自己查找啊!

Appium 的定位方式种类

我说的定位方式都是基于我自己亲测过,没使用或比较少用的就在这里不列举了,如有错误的地方,请多多包涵!常用的定位方式(仅限 Android 和 iOS 两种系统)有 className、id、xpath、AccessibilityId、AndroidUIAutomator、iOSNsPredicateString、iOSClassChain、IosUIAutomation 等

className

使用元素的className属性定位,支持:Android 和 iOS,推荐使用。
MobileBy.className("XCUIElementTypeButton")

id

使用元素的Resource Id属性定位,支持:Android,仅支持 Android 4.3 或以上,推荐使用。反正我没有在 iOS 用过,大家有正确使用过的例子,可以分享一下。
MobileBy.id("package.name:id/android")

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,'更多')]")

AccessibilityId

替代以前的name定位方式,推荐使用。
在 Android 上,主要使用元素的content-desc属性,如该属性为空,不能使用此定位方式。
在 iOS 上,主要使用元素的labelname(两个属性的值都一样)属性进行定位,如该属性为空,如该属性为空,也是不能使用该属性。
MobileBy.AccessibilityId("更多信息")

AndroidUIAutomator

仅支持 Android 4.2 或以上,可支持元素的单个属性和多个属性定位,推荐使用。
一种属性:MobileBy.AndroidUIAutomator("new UiSelector().text(\"发送\")")
两种属性:MobileBy.AndroidUIAutomator("new UiSelector().text(\"发送\").clickable(true)")
元素的所有属性都可用做定位,功能非常强大,且速度很快。

iOSNsPredicateString

仅支持 iOS 10 或以上,可支持元素的单个属性和多个属性定位,推荐使用。
一种属性:MobileBy.iOSNsPredicateString("type == 'XCUIElementTypeButton'")
两种属性:MobileBy.iOSNsPredicateString("type == 'XCUIElementTypeButton' AND label == '更多信息'")
具体 iOSNsPredicate 语法结构可查看官方文档,或查看的这个帖子:iOS 定位方式 iOSNsPredicateString 详解

iOSClassChain

仅支持 iOS 10 或以上,这是 github 的 Mykola Mokhnach 大神开发,仅限在 WebDriverAgent 框架使用,用于替代 xpath 的,但使用一阵子后,感觉灵活性没有 xpath 和 iOSNsPredicate 好,应该还不完善吧。具体使用方法,请见:https://github.com/appium/appium-xcuitest-driver/pull/391
MobileBy.iOSClassChain('XCUIElementTypeWindow[1]/XCUIElementTypeOther[1]/XCUIElementTypeOther[1]/XCUIElementTypeNavigationBar[1]/XCUIElementTypeOther[1]/XCUIElementTypeButton[2]')

IosUIAutomation

仅支持 iOS 9.3 或以下,是 iOS 旧框架 UIAutomation 的定位方式,现在基本上很少使用,这个定位类型同样可使用 iOS 谓词进行定位,详细可参考:iOSNsPredicate

总结:
以上这个多定位方式,很少说全部用完。根据我的经验,推荐使用:Android:AndroidUIAutomator > className = id = AccessibilityId > xpath。iOS:iOSNsPredicateString > className = AccessibilityId

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 48 条回复 时间 点赞
DC #25 · 2017年04月12日 Author

😭 居然没人回复

DC 回复

最近在做 iOS 的, 我一般是 By.name > By.className

DC #3 · 2017年04月13日 Author
fdeferf 回复

官方早就不推荐使用 name 的定位方式了,iOS 可以用 AccessibilityId 完全代替

iOS 目前主要用 xpath 和 name,官方推荐用 AccessibilityId,感觉跟 name 一样。目前主要问题的 desktop 在没有 name 或 AccessibilityId 情况下,不能提供 xpath,app-inspector 又各种任性不稳定,焦虑😪

DC 回复

类名是 MobileElement 对吧, 不是 WebElement

DC #6 · 2017年04月13日 Author
fdeferf 回复

都是用这个 MobileElement 的吧

DC #7 · 2017年04月13日 Author
lmlucky 回复

这个时候可以使用 iOS:iOSNsPredicateString,这个感觉还不错喔

DC 回复

好, 之前看官方示例, 有点乱, 有些地方是 MobileElement, 有些地方是 WebElement

DC #30 · 2017年04月13日 Author
fdeferf 回复

我自己统一使用 MobileElement

DC 回复

👍 赞,之前一直用的 webElement,现在看来还是狭隘,以后用 iOSDriver,多谢

DC 回复

多个元素相同的 className 怎么办? 用 MobileBy 怎么写

另外我发现, 如果用 MobileBy, 不能直接 click 等操作, 麻烦再多贴点代码

DC #12 · 2017年04月13日 Author
fdeferf 回复

可使用多个属性定位,找出两个属性就可以定位到,或者用 index 下标咯

DC 回复

麻烦贴点代码, 还有用 MobileBy 写后不能直接 click 等操作?

👍 整理的挺详细的,最后一段有笔误,ios 19.3。Mykola Mokhnach 对 selendroid inspector 做的二开,支持定位 ios 也提供 xpath 属性,目前用下来挺好的

感谢分享!

songz 回复

Mykola Mokhnach 的 xpath 怎么跟 iOS-inspector 不一样?是/AppiumAUT 开头的,代码定位不到元素。需要改造下么?

lmlucky 回复

拷贝之后被前面的去掉就行啦

lmlucky 回复

或者直接改他的处理好了

iOSNsPredicateString 用法详解,期待楼主新的分享

请问 @iOSXCUITFindBy(iOSNsPredicate ="")这个注解如何获取 List

songz 回复

果然是,多谢

DC #27 · 2017年04月24日 Author
test123123 回复

注解这种比较少研究,官方有例子的,可以参考下

3.通过元素的索引定位
MobileBy.xpath("//className[index]")
楼主,这种情况怎么看 index?比如我一个页面只有三个 value 值一样的 button 怎么定这个 index 呢?我这样写:@FindBy(xpath = "//XCUIElementTypeButton[@label = 'btn select n'][1]"),@FindBy(xpath = "//XCUIElementTypeButton[@label = 'btn select n'][2]"),只能定位到第一个

DC #24 · 2017年04月25日 Author
lmlucky 回复

这个 index 要根据这个元素所处在的上下节点有关系的,不能单独使用 index

DC 回复

嗯,明白了,已经用 findbys 返回的列表序号转化了,多谢

非常感谢

请问下 ios 可以用坐标定位元素吗?例如 frame

DC #47 · 2017年09月09日 Author
Trinity 回复

坐标定位是通用的

我有一个问题,python 好像用不了 AndroidUIAutomator
你知道为什么吗?

想问下楼主,本人 appium 版本 1.7.1 为什么没有找到使用 iOSNsPredicateString 来定位元素方式呢

DC #31 · 2018年01月10日 Author
江寒 回复

可以用的,名字都差不多,可能中间有_这个符号存在

DC #4 · 2018年01月10日 Author
cx 回复

有的,你要先将 driver 转为 IosDriver 才可以

楼主,一定要用 java-client 5 以上版本?还是 Appium 版本已经是 1.7.2-beta2 版本了就不用特意升级 java-client?

发现 java-client 升级到 5.0 以上,原有的好多 api 没法用,原有的长按、点击、滑动等,修改太大了

DC #6 · 2018年01月19日 Author
sini 回复

appium 最好是使用最新的 release 版本,java-client 也是如此,至于 api 改变大的话,自己可以封装成自己常用喜欢的就没啥问题了

DC 回复

好的,正在尝试中

DC 回复

java-client 升级了,appium 1.7.2+java-client 6.0.0-BETA2+Xcode 8.3.2

问题是用例运行的第一个需要等很久,以前 (java-client 4.1.2) 最多需要 1m30s,而现在升级了却要等 5m40s 还不一定。

请问大佬们有这个情况嘛?怎么做能减少这个时间

为什么我用不 iOSNsPredicateString 我用的是 appium1.8 python3.6 提示没有这个方法

DC #38 · 2018年05月25日 Author
锋子 回复

先将 driver 强制转换成 iOSdriver

使用 MobileBy.xpath 这种方式定位到元素后想获取元素的 text 用什么方法呢

HellenGo 回复

element.getText()

hello 回复

def get_title(self):
self.find_element(*self.title_loc).getText()

self.assertEqual("aa", self.withdraw_page.get_title())
报错,AttributeError: 'WebElement' object has no attribute 'getText'

DC #42 · 2018年09月07日 Author
HellenGo 回复

你要去 python client 源码上看看有没有这个方法或者类似的方法。你楼上的同学估计说的是 java client 方法

DC 回复

self.find_element(*self.btnNowLogin_loc).get_attribute("text") 可以的

HellenGo 回复

py 代码我不会,我是 java

楼主你好, 关于谓词定位的问题 (iOSNsPredicateString) 请教下...
有个场景需要使用 xpath 的父子定位和兄弟定位 (xpath 轴), 比如 xpath = "//XCUIElementTypeButton[@label = 'xyz']/following-sibling::XCUIElementTypeButton" 或者 xpath = "//XCUIElementTypeButton[@label = 'xyz']/.."
这样的父子元素和兄弟元素定位场景, 用 iOSNsPredicateString 有套路实现吗?或者用其它方式实现 (xpath 除外)...

(我从 Web 转过来的, 上面的对 App 的 xpath 例子可能没写好😨 ,大概是这么个意思哈)

DC #3 · 2018年11月12日 Author
chend 回复

可以先查找父元素,再查找子元素,appium 的 elements 有这个 API 的

DC 回复

是的, 已知父元素, 然后去查子元素这个我试了, ok 的.
反过来 已知子元素, 然后查父元素, 这个 api, 我翻了翻 Python 版的 Appium-Client 和 selenium 的源码, 没搜到类似功能的 API 呀,有这种吗?

DC #20 · 2018年11月15日 Author
chend 回复

没有发现有这个 API

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册