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

DC · April 11, 2017 · Last by DC replied at November 15, 2018 · 11360 hits

前言

使用过 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 #1 · April 12, 2017 作者

😭 居然没人回复

DC 回复

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

DC #3 · April 13, 2017 作者
mark 回复

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

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

DC 回复

类名是 MobileElement 对吧, 不是 WebElement

DC #6 · April 13, 2017 作者
mark 回复

都是用这个MobileElement的吧

DC #7 · April 13, 2017 作者
lmlucky 回复

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

DC 回复

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

DC #9 · April 13, 2017 作者
mark 回复

我自己统一使用 MobileElement

DC 回复

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

DC 回复

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

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

DC #12 · April 13, 2017 作者
mark 回复

可使用多个属性定位,找出两个属性就可以定位到,或者用 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 #22 · April 24, 2017 作者
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 · April 25, 2017 作者
lmlucky 回复

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

DC 回复

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

非常感谢

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

DC #28 · September 09, 2017 作者
Trinity 回复

坐标定位是通用的

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

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

DC #31 · January 10, 2018 作者
江寒 回复

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

DC #32 · January 10, 2018 作者
cx 回复

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

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

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

DC #34 · January 19, 2018 作者
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 · May 25, 2018 作者
锋子 回复

先将 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 · September 07, 2018 作者
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 #46 · November 12, 2018 作者
chend 回复

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

DC 回复

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

DC #48 · November 15, 2018 作者
chend 回复

没有发现有这个API

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up