这是iOS 9.3 系统之前自动化测试的架构模式。通过Android Appium 原理的学习 ,我们很容易理解 iOS Appium 原理:
Appium Client 端执行代码发送到 Appium Server端(Server 集成了苹果官方的 Instruments);
Server 端将一行行代码翻译成一条条指令,同时在手机上注入 bootstrap.jar ;
Server 与该 jar 包通信将指令传给 bootstrap.jar,jar 包调用手机里的自动化测试框架(UIAutomation),UIAutomation框架执行指令。
通过 Android Appium 原理的学习,Android 4.4 系统之后,Appium 支持使用 ChromeDriver 进行对 Hybrid 页面的自动化测试。那么 iOS 上是怎么做的呢?
iOS 上早期苹果官方就一直提供 iOS webkit debug proxy(这是苹果官方自己开发的私有的通信协议),Appium 集成了该框架,通过它传递指令。
Appium 在 iOS 下工具的变革
但是 WebDriverAgent 仅仅只提供了一个 server(和 inspect 进行元素定位),并没有像 Appium 一样提供 java 或 python 的 Client 端去写脚本,脚本执行的时候发送指令给 server,然后去运行。WebDriverAgent 要求你自己去实现 Client 端,即拿 Java/ Python 的 WebDriver 库进行封装,然后发送指令。 所以 WebDriverAgent 其实就类似于 Appium server,就只是一个 server。
Appium 很粗暴的把整个 WebDriverAgent 直接集成到自己的项目里,然后通信机制就走 WebDriverAgent,Appium 其实就提供了一个 Client 端的作用。
所以 iOS 9.3 系统之后自动化测试核心是 WebDriverAgent,Appium 就提供了一个 Client 端来写脚本和发送指令。
通过前面的学习,我们知道 Appium 自动化架构模式可以用一个抽象的架构表示,就是下面这样的:
iOS 9.3以及之后的 Appium 自动化架构模式如下图所示:
从图中可以看出:
Client 端是 Appium 之前本身提供的;
Server 端是:WebDriverAgent 和 Instruments;( Appium 直接把 WebDriverAgent 整个集成进来,Instruments 是为了支持 iOS 9.3 之前的系统)
最右边是一个手机
Xcode、command line tool、libimobiledevice、ios-deploy、carthage、WebDriverAgent、Appium。
其常用命令如下:
查看当前所连接的设备
idevice_id -l # 显示当前所连接设备的 udid
instruments -s devices # 列出所有设备,包括真机、模拟器、mac
安装应用
ideviceinstaller -u [udid] -i [xxx.ipa] # xxx.ipa 为应用在本地的路径
卸载应用
ideviceinstaller -u [udid] -U [bundleId]
查看设备已安装的应用
ideviceinstaller -u [udid] -l # 查看设备安装的第三方应用
ideviceinstaller -u [udid] -l -o list_user # 同上,查看设备安装的第三方应用
ideviceinstaller -u [udid] -l -o list_system # 查看设备安装的系统应用
ideviceinstaller -u [udid] -l -o list_all # 查看设备安装的所有应用
获取设备信息
ideviceinfo -u [udid] # 获取设备信息
ideviceinfo -u [udid] -k DeviceName # 获取设备名称 同命令 idevicename
idevicename # 同上
ideviceinfo -u [udid] -k ProductVersion # 获取设备版本 10.3.3
ideviceinfo -u [udid] -k ProductType # 获取设备类型 iPhone 8,1
ideviceinfo -u [udid] -k ProductName # 获取设备系统名称
ideviceinfo # 获取设备所有信息
idevicesyslog # 获取设备日志
idevicecrashreport -e test # 获取设备 crashlog,test 是文件夹需新建
idevicediagnostics # 管理设备状态 - 重启、关机、睡眠等
ios-deploy -c # 查看当前链接的设备
ios-deploy --[xxx.app] # 安装APP
ios-deploy --id [udid] --uninstall_only --bundle_id [bundleId] # 卸载应用
ios-deploy --id [udid] --list_bundle_id # 查看所有应用
ios-deploy --id [udid] --exists --bundle_id # 查看应用是否安装
公司 iOS 项目也使用 carthage,类似于 java 的 maven;
ios-deploy、ideviceinstaller 类似 android 的 adb;
authroize-ios,iOS 授权工具,主要用于模拟器中一些权限的授权;
npm install -g authroze-ios
sudo authroze-ios
从 FB 的 GitHub 上下载WebDriverAgent
GitHub 上下载WebDriverAgent
初始化项目
在 WebDriverAgent 目录下执行:./Scripts/bootstrap.sh
编译 WebDriverAgent
a. open WebDriverAgent.xcodeproj(会使用默认打开工具Xcode打开项目)。
b. 修改 WebDriverAgent.lib 以及 WebDriverAgentRunner 这两个 target 下的 General 和 Build Settings列表(前者是在 mac 上运行的,后者是在手机上运行的)。
c. General 列表需要修改:签名 Signing 和 BundleId: 签名 Signing:可以用个人免费开发者证书,用任意 AppleId 可申请;BundleId:之前 BundleId 是绑定了 FB team 的证书的,不能使用,所以要改一个新的。 Build Settings列表需要修改 BundleId 和 上一步一样。
d. WebDriverAgentRunner 是在手机上运行的,要想在手机上安装,需要和上一步一样修改 General 和 Build Settings 列表。
e. 手机上设置 - 通用 - 描述文件 里信任一下该证书。
f. Xcode - Product - Test,会安装 WebDriverAgentRunner 并启动 WebDriverAgent 这个 server。
替换 Appium 下的 WebDriverAgent:删除原 WebDriverAgent 文件夹,把编译好的 WebDriverAgent 放进去即可
a . 如果用 npm 安装的目录在:cd /usr/local/lib/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent/;
b. 如果用 desktop 安装的目录在:/Applications/Appium.app/Contents/Resources/app/node_modules/appium/node_modules/appium-xcuitest-driver/WebDriverAgent/)
这里我们需要将TestApp重新编译才能使用。
进入 APP 其 xxx.xcodeproj 对应的目录,open WebDriverAgent.xcodeproj 打开项目;
修改该项目里 target 的 General 和 Build Settings列表(和上面一样);
通过 Xcode 编译运行。
或者通过 xcodebuild 命令通过命令行编译运行 xcodebuild -project TestApp.xcodeproj -target TestApp -sdk iphoneos10.3 -configuration
development
iOS 项目的 Desired_caps
Desired_caps:{
’platformName’:’iOS’,
‘platformVersion’:’10.3.3’,
‘devideName’:’iPhone 7 Plus’,
‘udid’:’’, #如果是真机的话必须提供
‘app’:’~/appPath/app.app’, #app路径,如果只填bundleId,那就是通过id启动已有的App
}
iOS 的元素定位
Appium Desktop - Inspect (推荐)
WebDriverAgent - Inspector
这里说说 Appium Desktop - Inspect 是怎么使用的。
-打开并启动 Appium Desktop,点击软件右上角第一个按钮 “ start inspector session”;
-会出现弹窗,弹窗里配置好 Desired_caps。
其他Desired_caps配置参见官方文档:https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md
注意
webdriver.py 里只延展定义了针对移动端的 API,is_displayed()、.is_enabled()() 等这些 API 可以去看 WebDriver 即 Slenium 2 本身的。
WebDriver 本身的 API 详见
原文链接:https://testerhome.com/topics/10068
由于使用id、className、AccessibilityId定位方式较为简单,多数情况下,在同一个页面,都不是唯一存在的,不能识别一个元素。而 xpath定位方式在 xcui 底层原生不支持,由 appium 额外支持的,定位速度很慢,而且有时候定位不到元素的情况存在。综上所述,在 iOS 的 UI 自动化中,使用原生支持的iOSNsPredicateString定位方式是最好,支持也是最好的。
iOS 版本全支持,底层测试框架无论是XCUITest 或 UIAutomation,可支持元素的单个属性和多个属性定位,推荐使用。一个元素有这些属性:type、value、name、label、enabled、visible,有些元素的属性只有以上的部分属性,如下图所示,可根据这些属性进行元素定位
type:元素类型,与className作用一致,如:XCUIElementTypeStaticText
value: 一般不用
name:元素的文本内容,可用作 AccessibilityId定位方式,如:测试420班级群
label:绝大多数情况下,与 name 作用一致
enabled:元素是否可点击,一般值为true或者false
visible:元素是否可见,一般值为true或者false
元素的定位方式都是一个属性+运算符+值形式存在
1、比较运算符:>,<,==,>=,<=,!=
可用于数值和字符串的比较,
如:name>100 或name == ‘测试’
2、范围运算符:IN,BETWEEN
可用于数值和字符串的范围核对
如:name BETWEEN {3,10},name IN {‘Alan’,‘May’}
3、字符串相关:CONTAINS、BEGINSWITH、ENDSWITH
包含某个字符串,如:label CONTAINS ‘测试’
以某个字符串开头,如:label BEGINSWITH ‘420’
以某个字符串结束,如:label ENDSWITH ‘班级群’
PS:在三个关键字后加上[c]不区分大小写,可用于字母的校验;[d]不区分发音符号,即没有重音符号($、#、%等);[cd]即不区分大小写,也不区分发音符号,如:name CONTAINS[c] ABcd和name CONTAINS abcd、name CONTAINS ABCD是等同的,注意后面两个没带[c]的不相等
4、通配符:LIKE
通配符也接受[cd],?代表一个字符,*代表多个字符
如:一个元素的label属性为
label LIKE ‘420测试班级群’
label LIKE ‘420测?班级群’
label LIKE ‘420??班级群’
label LIKE ‘42?测试班?群’
label LIKE ‘*试班级群’
label LIKE ‘420测试班*’
label LIKE ‘42*级群’
label LIKE ‘4试群’
以上这么多种文本都可以被识别为同一个元素。
5、正则表达式:MATCHES
如:以4开头,以群结束,
label MATCHES ‘^4.+群$’
可以用元素的属性:type、value、name、label、enabled、visible,进行定位:
type == XCUIElementTypeStaticText,
label CONTAINS ‘测试’
label LIKE ‘*试班级群’
enabled == true
visible == false
就是以上单个属性定位用符号AND连接起来即可。如:
type == XCUIElementTypeStaticText AND labelCONTAINS '测试
type == XCUIElementTypeStaticText AND labelCONTAINS ‘测试’ AND enabled == true
#父子关系定位
self.driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/title_container").childSelector(text("股票"))')
#兄弟关系定位
self.driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/title_container").fromParent(text("股票"))')
#滚动查找
self.driver.find_element_by_android_uiautomator('new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("查找的元素文本").instance(0));')
// 等于
MobileElement photo = driver.findElementByIosNsPredicate("name= ‘head new‘");
// 模糊匹配
MobileElement photo =driver.findElementByIosNsPredicate("name LIKE ‘*new‘");
// 正则表达式匹配
MobileElement photo = driver.findElementByIosNsPredicate("nameMATCHES ‘^$‘");
// 包含
List<IOSElement> items1 = driver.findElementsByIosNsPredicate("nameCONTAINS ‘我的‘");
// 以"我的"开始
List<IOSElement> items2 = driver.findElementsByIosNsPredicate("nameBEGINSWITH ‘我的‘");
// 以"我的"开始并且以"消息"结尾
List<IOSElement> items3 = driver.findElementsByIosNsPredicate("nameBEGINSWITH ‘我的‘ && name ENDSWITH ‘消息‘");
其中属性名参照inspector的属性字段,关键字LIKE,MATCHES,CONTAINS,BEGINSWITH,ENDSWITH必须是大写,匹配的字符需要用单引号
小坑建议:
可以参考:
wangmcn84作者的模拟器
真机自动化环境搭建
真机自动化环境搭建-实际操作
http://10.0.223.58:8100/status
如果是想查看UI的图层,则可访问http://localhost:8100/inspector,方便书写测试用 已废弃
查找元素的顺序,从快到慢:
ios_predicate >> accessibility_id >> class_name >>xpath
(论坛比较多的说法是class_name>>accessibility_id,在这里我们姑且认为它们的速度是一样的。)
appium测试-操作Android非原生View(自定义)控件(如部分日期和地点选择下拉控件),基于JavaCV的图像匹配方法
Appium使用swipe定位滚动列表和滚动屏幕元素
iOS 测试 ios+appium 自动化 click 无效
问题现象
app 页面上可以看到元素,并且通过 find_element_by_xpath 方法也可以定位到,但操作 click 后,页面并未如预期进行跳转,点击实际上没有生效
问题原因
通过 self.driver.page_source 获取页面 xml,发现元素属性 visible=‘false’,导致 click 不生效
解决方法
用 TouchAction 方法,通过坐标进行点击,python 实现如下
def touch_on_ele(self, ele):
x_pos = ele.location['x'] + ele.size['width'] / 2
y_pos = ele.location['y'] + ele.size['height'] / 2
TouchAction(self.driver).tap(x=x_pos, y=y_pos).perform()
思路:如果控件的属性visible是false的话,请使用控件坐标并获取中心点用tap点击,直接点击控件会失败
需要引入 TouchAction 库
from appium.webdriver.common.touch_action import TouchAction
元素错位 卸载腾讯tbs
IOS原生定位不支持纯数字匹配
目前,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 应用自动化的定位方式
详细可以参考:https://zhuanlan.zhihu.com/p/28625273