Appium iOS 元素定位与操作
概述
iOS App和Android App由于系统差异原因,元素属性和定位方式也存在一些差异,之前分享过Android 元素定位方式, 本篇博文分享iOS App元素定位方式。
运行环境
1.硬件环境
设备类型 | 系统版本
—|—
Mac-mini | Mac OS 10.14.6
iPhone6 | iOS 12.4.3
2.软件环境
软件类型 | 系统版本
—|—
Appium-desktop | 1.15.0.1
iOS自动化框架
对于 iOS 自动化,Appium 依赖苹果提供的系统框架。对于 iOS 9.2
及更低版本,苹果唯一的自动化技术被称为UIAutomation
,它运行在 Instruments
中。从 iOS 10
开始,苹果已经完全删除了 UIAutomation
工具,因此 Appium 不可能按照以前的方式进行测试。同时,苹果推出了一款名为 XCUITest
的新型自动化技术,从 iOS 9.3
到 iOS 10
及以上版本,这将是苹果唯一支持的自动化框架。
Appium 从 Appium 1.6
开始支持 XCUITest
。因此对于iOS 9.2
以下的系统需要使用UIAutomation
方式定位,iOS 9.2
以上的版本需要使用 XCUITest
定位。考虑到目前iOS
系统更新到了iOS13
(截止到2019.12.19) iOS 9.2
以下系统属于比较老旧系统,设备覆盖率相对较低,所以主要讲解基于XCUITest
的元素定位方式。一般在初始化driver时也会指定automationName
的值为XCUITest
1 | desired_caps['automationName']='XCUITest' |
元素定位工具
Android 和iOS元素常用定位工具如下表所示:
工具 | 支持平台 | 说明 |
---|---|---|
appium-inspector | android,iOS native | 官方appium-desktop安装包自带, 命令行安装没有该工具 |
app-inspector | android,iOS native | 阿里开源的macaca框架带的工具, 可以单独安装:npm install -g app-inspector |
UIAutomatorviewer | android native | android sdk自带工具软件 |
Chrome Inspect | android,iOS webview | android webview可以直接使用, iOS webview需要安装ios-webkit-debug-proxy 并且以ios_webkit_debug_proxy -f chrome-devtools://devtools/bundled/inspector.html 启动使用; |
这里我们使用Appium的Appium-desktop工具来获取元素,下载Appium-desktop Mac版(dmg结尾的包名) 然后配置应用参数启动Appium-desktop,不太清楚操作流程可以参考之前的博文: Appium capability参数配置简介 启动appium成功之后可以看到如下界面:
iOS元素类型与属性
元素常用类型
在 XCUITest 中,苹果已经为构成视图层次结构的 UI 元素提供了不同的类名。例如 XCUIElementTypeButton
表示按钮类型元素。从上面的元素结构视图我们可以看到下面这些常用的元素类型。
- XCUIElementTypeApplication: 应用类型,一般位于根节点
- XCUIElementTypeWindow:窗口类型元素可以包含按钮,文字用于布局。
- XCUIElementTypeStatusBar:状态类型
- XCUIElementTypeOther:自定义类型
- XCUIElementTypeCollectionView:集合视图
- XCUIElementTypeCell:元件类型
- XCUIElementTypeTable:表格类型
- XCUIElementTypeStaticText:文字类型
- XCUIElementTypeButton:按钮类型
元素属性
每个元素都有不同的属性值,常用属性值如下:
type
:元素类型,与className
作用一致,如:XCUIElementTypeButton
value
: 元素值name
:元素的文本内容,可用作 AccessibilityId定位方式,如:ClearEmaillabel
:元素标记;绝大多数情况下,与 name 作用一致enabled
:元素是否可点击,一般值为true或者falsevisible
;元素是否可见,一般值为true或者false
元素定位策略
ios_predicate
在 iOS 的 UI 自动化中,使用原生支持的Predicate
定位方式是最好,可支持元素的单个属性和多个属性定位,属性值还可以使用精确和模糊匹配,强烈推荐使用!
单个/多个属性定位
1 | driver.find_element_by_ios_predicate("value == 'ClearEmail'") |
多个属性可以使用关键词AND
连接。
属性值匹配——比较运算符
Predicate
定位方式支持比较运算符:>、<、==、>=、<=、!=
可用于数值和字符串的比较:
1 | driver.find_element_by_ios_predicate("value>100") |
属性值匹配——范围运算符
支持范围运算符:IN、BETWEEN
,可用于数值和字符串的范围核对
1 |
|
属性值匹配——字符串相关
字符串相关语法:CONTAINS、BEGINSWITH、ENDSWITH
1 |
|
属性值匹配——通配符
通配符: LIKE
其中:?
代表一个字符,*
代表多个字符
如:一个元素的value属性为ClearEmail:
1 |
|
属性值匹配——正则表达式
正则表达式:MATCHES
如:一个元素的value属性为ClearEmail
,则可以如下定位。
1 |
|
获取多个元素
如果要获取一组属性相同的元素,则需要使用def find_elements_by_ios_predicate()
方法
1 | def find_elements_by_ios_predicate(self, predicate_string): |
accessibility_id
该定位方式主要使用元素的label
或name
(两个属性的值都一样)属性进行定位,如该属性为空,也是不能使用该属性。
1 | driver.find_element_by_accessibility_id('ClearEmail') |
class_name
使用元素的type
属性定位,特别注意该属性的唯一性!class_name
唯一的情况并不多,一般情况下用不上。
1 | driver.find_element_by_class_name('XCUIElementTypeButton') |
class_chain
类链定位方法 仅支持 iOS 10
或以上,这是 github 的 Mykola Mokhnach 大神开发,仅限在 WebDriverAgent 框架使用,用于替代 xpath.
1 | driver.find_element_by_ios_class_chain('XCUIElementTypeWindow/XCUIElementTypeButton[3]') # 选择第一个子窗口元素的第三个子按钮 |
相对定位
相对定位是根据元素层级关系先定位到父级元素,然后再进一步定位目标元素。
1 |
|
xpath
xpath定位是一种路径定位方式,主要是依赖于元素绝对路径或者相关属性来定位,但是绝对路径xpath执行效率比较低(特别是元素路径比较深的时候)由于iOS 10开始使用的 XCUITest 框架原声不支持,定位速度很慢,所以官方现在不推荐使用。
xpath路径表达式
表达式 | 描述 |
---|---|
/ | 从根节点选取。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
nodename | 选取此节点的所有子节点。 |
. | 选取当前节点。 |
.. | 选取当前节点的父节点。 |
@ | 选取属性。 |
xpath匹配符
通配符 | 描述 |
---|
- | 匹配任何元素节点。
@* | 匹配任何属性节点。
node() | 匹配任何类型的节点。
1 | driver.find_element_by_xpath("/XCUIElementTypeWindow[1]/XCUIElementTypeOther/XCUIElementTypeOther") |
Xpath轴
XPath轴可定义相对于当前节点的节点集,语法格式如下:
1 | 轴名称::节点测试[谓语] |
轴名称 | 结果 |
---|---|
ancestor | 选取当前节点的所有先辈(父、祖父等)。 |
ancestor-or-self | 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。 |
attribute | 选取当前节点的所有属性。 |
child | 选取当前节点的所有子元素。 |
descendant | 选取当前节点的所有后代元素(子、孙等)。 |
descendant-or-self | 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。 |
following | 选取文档中当前节点的结束标签之后的所有节点。 |
namespace | 选取当前节点的所有命名空间节点。 |
parent | 选取当前节点的父节点。 |
preceding | 选取文档中当前节点的开始标签之前的所有节点。 |
preceding-sibling | 选取当前节点之前的所有同级节点。 |
following-sibling | 选取当前节点之后的所有同级节点 |
self | 选取当前节点。 |
示例
1 | xpath=//XCUIElementTypeStaticText[@name="登录/注册"]/preceding-sibling::XCUIElementTypeButton[1] |
上面语法表示获取属性为name="登录/注册
的元素的同级节点中第一个XCUIElementTypeButton
元素
更多示例如下表:
例子 | 结果 |
---|---|
child::book | 选取所有属于当前节点的子元素的 book 节点。 |
attribute::lang | 选取当前节点的 lang 属性。 |
child::* | 选取当前节点的所有子元素。 |
attribute::* | 选取当前节点的所有属性。 |
child::text() | 选取当前节点的所有文本子节点。 |
child::node() | 选取当前节点的所有子节点。 |
descendant::book | 选取当前节点的所有 book 后代。 |
ancestor::book | 选择当前节点的所有 book 先辈。 |
ancestor-or-self::book | 选取当前节点的所有 book 先辈以及当前节点(如果此节点是 book 节点) |
child::*/child::price | 选取当前节点的所有 price 孙节点。 |
扩展资料:xpath语法
元素操作方法
定位到元素之后我们一般会模拟用户进行点击,文本输入,滑动等操作,那么该如何进行这些操作呢。
点击
点击操作可以直接使用click()
方法来进行点击即可。
1 | driver.find_element_by_ios_predicate("value == 'ClearEmail'").click() |
文本操作
对于文本框元素,我们可以使用send_keys()
方法来输入文字,使用clear()
方法来清除文本框内容。
1 | elem = self.driver.find_element_by_ios_predicate( |
坐标点点击
对于有些元素无法使用常规的定位方式来点击,这个时候我们可以根据坐标点来进行点击操作。这个和Android app元素操作是一样的。
1 | from appium.webdriver.common.touch_action import TouchAction |
滑动
滑动操作也和Android app应用操作一样,详见之前的博文: Appium滑动操作
报错相关
- 定位连接中断
1
ProtocolError: ('Connection aborted.', ConnectionResetError(54, 'Connection reset by peer'))
- 报错原因:Appium 服务超时中断,
- 解决方案:可以设置
newCommandTimeout
延长,默认是60s,然后重启appium服务,升级openssl版本。还有一种可能是需要升级openssl
升级方法见:Mac 升级/更新openSSL版本