iOS 自动化测试:Appium 架构原理、环境命令、定位方式

1、原理与变迁

1.1 环境版本变迁

先来看下面的版本对应表
在这里插入图片描述
由上表可以得知:

iOS 8.0到9.3 之间的时候一直以 instruments 下的 UIAutomation为驱动底层技术

查阅资料说弊端是由于 instruments 的限制,单台 mac 只能对应单台设备,由于现在9.3之前的版本很少了,所以我在学习的时候也就忽略了这部分的内容,仅作为了解);

iOS 9.3 之后的版本推出 XCUITest 工具,用以替代 UIAutomation,这个时候Appium需要1.6.0以上的版本才可以支持;

截止我写这篇博客,appium的版本已经更新到了1.20.2,所以这个也不用担心版本不够的问题了

再来看Appium对IOS原生定位方式Predicate的一段说明
在这里插入图片描述
Appium要求在iOS 10以上版本才可以用此方法,因为iOS 10之后苹果直接废弃了 UIAutomation(Xcode8之后);而Facebook 推出 WebDriverAgent成为了主流(实现的 server 能够支持单台 mac 对应多个设备);
Appium 在iOS 9.3 后全面采用 WebDriverAgent 的方案。
上面提到了XCUITest、WebDriverAgent,现在又说用appium,那么他们之间到底是什么关系,用appium做IOS自动化的架构原理又是如何?

1.2 架构原理

XCUITest是苹果开发的一个做IOS自动化测试的框架,需要了解些Swift等iOS编程知识
WebDriverAgent是Facebook开发的一个iOS自动化测试工具,先来看下面的这张原理图:
在这里插入图片描述
WDA在Client创建了一个Server,在手机端安装了一个叫作WebDriverAgentRunner 的一个应用;这个应用会接收来自 Server 的指令,并连接底层的 XCTest.framwork,让 XCTest.framwork 调用苹果API来操作手机进行自动化
而appium是把WebDriverAgentRunner 给集成进去了,因此实现了appium的跨平台能力
在这里插入图片描述

2、环境命令

这里对安装运行过程中的一些命令和环境问题做个总结归纳,具体的实施细节和踩坑可参考上一篇博客:
iOS自动化测试(一)-技术方案、环境配置与疯狂踩坑

2.1 常用命令

这里发现testerhome社区有位同学总结的很全面细致,就直接引用了,章节末尾会附上原文链接

1)、libimobiledevice / ideviceinstaller 库,相当于 android 的 adb,是 Appium 底层用到的工具之一,用于获取 iOS 设备信息,常用命令如下:

  • 查看当前所连接的设备
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 # 管理设备状态 - 重启、关机、睡眠等

2)ios-deploy 常用命令

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 # 查看应用是否安装

3) carthage,项目依赖管理,主要是 WebDriverAgent 使用,WebDriverAgent 是用它做项目依赖的;
公司 iOS 项目也使用 carthage,类似于 java 的 maven;

4) ios-deploy、ideviceinstaller 类似 android 的 adb;

5) authroize-ios,iOS 授权工具,主要用于模拟器中一些权限的授权;

npm install -g authroze-ios
sudo authroze-ios

2.2 环境总结

上面提到的那位同学依然总结的很好,因为原文注明了禁止转载,所以尊重原创(原创确实不易,自己写博客就会有体会~)这部分就直接附上链接,供大家去原文参考:
https://testerhome.com/topics/10068
当然,具体的实施细节有需要的伙伴依然可以参考我之前的文章
在这里插入图片描述

3、Appium的iOS自动化实现

这里使用上一篇介绍的appium自带的测试软件UICatalog来进行演示

3.1 控件属性获取

在Android自动化的时候,我们用uiautomatorview或者appium-desktop可以实现dom的解析以获取元素属性,iOS同样也有两种方法:
1)WebDriverAgent - Inspector
在WDA启动后,浏览器输入http://192.168.0.105:8100/inspector便可以得到如下场景
在这里插入图片描述
但是这个工具不是很好用,无法进行交互且可能因为环境版本问题而造成使用不顺利,所以我们还是推荐使用appium-desktop
2)appium-desktop
这个对于用appium做过移动端自动化的应该很熟悉了,打开解析后就是如下场景
在这里插入图片描述

3.2 定位方式
以定位Buttons并点击为例

从上图的dom中我们可以看到iOS的控件有typevaluenamelabel等属性

name和label大多数都是一样的,可以把name理解为id,直接使用AccessibilityId可以完成定位(也是最常用的定位方式):

iosDriver.findElementByAccessibilityId("Buttons").click();

iOS自动化还支持原生IosNsPredicate定位方式,这种方式灵活度很高,可以指定任意属性:

iosDriver.findElementByIosNsPredicate("value=='Buttons'").click();
iosDriver.findElementByIosNsPredicate("label=='Buttons'").click();
iosDriver.findElementByIosNsPredicate("name=='Buttons'").click();

上面的是用"=="的形式,也是最常用的一种方式,除此之外,官网说明中还提供了各种吧运算符和逻辑符号等:

  • 基础比较
    >= , =>:大于或等于
    <= , =<:小于或等于
    >:大于
    <:小于
    != , <>:不等于
    BETWEEN:介于两数之间(闭区间)
  • 布尔值
    TRUEPREDICATE:值一直为true
    FALSEPREDICATE:值一直为false
  • 逻辑操作符
    AND , && - Logical AND.
    OR , || - Logical OR.
    NOT , ! - Logical NOT.
    经常在需要多个属性一起定位的时候就常用AND
iosDriver.findElementByIosNsPredicate("type=='XCUIElementTypeStaticText' AND name=='Buttons'").click();
  • 字符串比较
    BEGINSWITH:以什么开头
    CONTAINS:包含
    ENDSWITH:以什么结尾
    MATCHES:正则表达式比较
  • Xpath
    当然少不了万能的Xpath,iOS自动化也支持xpath定位:
iosDriver.findElementByXPath("(//*[@type='XCUIElementTypeStaticText'])[7]" ).click();

还有很多操作,例如LIKE通配符等,因为平常用到的比较少,我也就没继续研究,绝大多数情况使用AccessibilityIdxpathIosNsPredicate配上简单的比较符就足够了,感兴趣研究的同学可参考官网:
http://appium.io/docs/en/writing-running-appium/ios/ios-predicate/index.html#boolean-value-predicates

3.3 Capabilities设置

这里仅列出与Android自动化中Capabilities设置不同的地方

  • platformName:系统名,填写ios
  • deviceName:设备名称,Android中只要有值就行,但是iOS中需要你填写正确的设备名称,可以使用instruments -s命令查找
  • platformVersion:手机的系统版本,填写9.3以上就可以了,因为之前介绍过appium在iOS 9.3版本以后才支持 XCUITest ;实测填写9.3以前的版本会报错
    在这里插入图片描述

这个参数可能还和appium的版本有关,实测使用appium-desktop自带的1.15版本的server,不使用platformVersion也可以运行成功,本地的1.14版本的appium-server运行就必须有此参数;所以保险起见还是都加上为好。

  • udid:手机的id号,真机的时候需要填写,可以通过idevice_id -l命令获得,也可以填写auto,系统会自动执行idevice_id命令去获得
  • xcodeOrgId:签名ID,在使用苹果账号构建完成项目后悔生成一个ID号,在构建记录中的sign中获取
    在这里插入图片描述
  • bundleId:需要启动的应用的bundleId,类似于Android中的包名一样
    在这里插入图片描述
  • xcodeSigningId:固定写法,填写iPhone Developer
  • automationName:填写XCUITest,指定使用XCUITest定位
  • usePrebuiltWDA:填写true的话就使用上一次加载好的WDA,增加执行效率
  • app:填写App在本地的路径
    以上就是常用的一些基本的Capabilities配置,其他更多的配置可参考官方文档:
    http://appium.io/docs/en/writing-running-appium/caps/index.html#ios-only-using-xcuitest
    https://github.com/appium/appium-xcuitest-driver

4、举例验证

理论需要实践来论证,检验一下实际运行效果

4.1 测试代码

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author:chenshifeng
@file:test_ios.py
@time:2021/02/24
"""
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy


class TestIos:
    def setup(self):
        desired_caps = {}
        desired_caps['platformName'] = 'iOS'
        # desired_caps['platformVersion'] = '13.6'
        desired_caps['platformVersion'] = '14.2'
        # desired_caps['deviceName'] = 'SFdeiPad'
        desired_caps['deviceName'] = 'SFdeiPhone'
        desired_caps['bundleId'] = 'com.chenshifeng.apple-samplecode.UICatalog'
        desired_caps['udid'] = 'auto'
        desired_caps['xcodeOrgId'] = 'UYJV48339N'
        desired_caps['xcodeSigningId'] = 'iPhone Developer'

        self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
        self.driver.implicitly_wait(10)

    def test_ios(self):
        self.driver.find_element(MobileBy.ACCESSIBILITY_ID,'Action Sheets').click()
        self.driver.find_element(MobileBy.ACCESSIBILITY_ID,'Other').click()
        self.driver.find_element(MobileBy.ACCESSIBILITY_ID,'Safe Choice').click()

    def teardown(self):
        self.driver.quit()

以上所有的定位方式均实际运行测试通过

参考链接:

appium官方相关:
http://appium.io/docs/en/drivers/ios-xcuitest/
http://appium.io/docs/en/writing-running-appium/finding-elements/
http://appium.io/docs/en/writing-running-appium/caps/index.html#appium-desired-capabilities
http://appium.io/docs/en/drivers/ios-xcuitest-real-devices/
http://appium.io/docs/en/commands/element/find-element/
http://appium.io/docs/en/writing-running-appium/ios/ios-predicate/index.html#boolean-value-predicates
https://github.com/appium/appium-xcuitest-driver
testerhome相关:
https://testerhome.com/topics/4904
https://testerhome.com/topics/10068
Facebook官方相关:
https://github.com/facebookarchive/WebDriverAgent
https://github.com/facebookarchive/WebDriverAgent/wiki/Starting-WebDriverAgent
简书相关:
https://www.jianshu.com/p/422741e37ece
————————————————

原文链接:https://blog.csdn.net/weixin_43291944/article/details/103601834


版权声明:本文为shifengboy原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。