使用facebook-wda进行iOS APP自动化测试
facebook-wda 是一个基于Python的测试库,通过HTTP协议与WebDriverAgent通信,本文介绍如何使用 facebook-wda 进行iOS APP自动化测试。目录环境准备初始化创建一个客户端设备操作打开、停止App获取设备应用信息查看设备状态信息获取应用信息获取设备信息UI元素定位基本选择器子元素多个实例XPath定位Predicate定位classChain定位获取元素
facebook-wda 是一个基于Python的测试库,通过HTTP协议与WebDriverAgent通信,本文介绍如何使用 facebook-wda 进行iOS APP自动化测试。
目录
环境准备
使用 facebook-wda 之前需要满足如下条件:
-
手机安装 WebDriverAgent应用
- 可以使用xcodebuild启动WDA(需要MAC电脑)
- 也可以使用tidevice启动,它可以在Linux 、Windows和MAC上使用
-
电脑安装facebook-wda:
pip3 install -U facebook-wda
在windows上搭建iOS自动化测试环境可参考:Windows上实现iOS APP自动化测试:tidevice + WebDriverAgent + facebook-wda / appium
本文使用tidevice启动WDA:
$ tidevice list
List of apple devices attached
00008101-000255021E08001E iPhone12
$
$ tidevice -u [设备 udid] wdaproxy -B [wda 的 bundle Id] --port 8100
可以使用weditor查看UI元素,注意使用它之前要启动WDA。
pip3 install -U weditor # 安装
命令窗口输入weditor,会自动打开一个浏览器,选择iOS。
环境准备好后就可以使用facebook-wda进行iOS APP自动化测试了。
初始化
全局配置
import wda
wda.DEBUG = False # default False
wda.HTTP_TIMEOUT = 180.0 # default 180 seconds
wda.DEVICE_WAIT_TIMEOUT = 180.0
DEBUG设置为 True
时会显示HTTP请求和响应信息
>>> import wda
>>> wda.DEBUG = True
>>> wda.HTTP_TIMEOUT = 180.0
>>> wda.DEVICE_WAIT_TIMEOUT = 180.0
>>> c = wda.Client('http://localhost:8100')
>>> c.app_current()
Shell$ curl -X GET -d '' 'http://localhost:8100/wda/activeAppInfo'
Return (206ms): {
"value" : {
"processArguments" : {
"env" : {
},
"args" : [
]
},
"name" : "",
"pid" : 228,
"bundleId" : "com.apple.Preferences"
},
"sessionId" : null
}
{'processArguments': {'env': {}, 'args': []}, 'name': '', 'pid': 228, 'bundleId': 'com.apple.Preferences'}
>>>
>>> wda.DEBUG = False
>>> c.app_current()
{'processArguments': {'env': {}, 'args': []}, 'name': '', 'pid': 228, 'bundleId': 'com.apple.Preferences'}
>>>
创建一个客户端
import wda
c = wda.Client('http://localhost:8100')
c = wda.Client() # 读取环境变量DEVICE_URL,如果没有使用默认地址:http://localhost:8100
也可以使用USBClient连接设备:
c = wda.USBClient() # 仅连接一个设备可以不传参数
c = wda.USBClient("00008101-000255021E08001E", port=8100) # 指定设备 udid 和WDA 端口号
c = wda.Client("http+usbmux://{udid}:8100".format(udid="00008101-000255021E08001E")) # 通过DEVICE_URL访问
c = wda.USBClient("00008101-000255021E08001E", port=8100, wda_bundle_id="com.facebook.WebDriverAgent.test2.xctrunner") # 1.2.0 引入 wda_bundle_id 参数
注:初始化连接设备时不需要事先使用tidevice命令启动WDA,wda.Client()会自动启动WDA应用。
设备操作
等待WDA服务正常
c.wait_ready(timeout=120, noprint=True) # 默认120s,安静的等待,无进度输出
锁屏
>>> c.locked()
False
>>> c.lock()
{'value': None, 'sessionId': '4D60BDFB-5D18-4EFB-8C40-97E4826B9AAB', 'status': 0}
>>> c.unlock()
{'value': None, 'sessionId': '4D60BDFB-5D18-4EFB-8C40-97E4826B9AAB', 'status': 0}
回到手机主页面
c.home()
c.press("home")
增大降低音量
c.press("volumeUp")
c.press_duration("volumeUp", 1) # 长按1s
c.press("volumeDown")
c.press_duration("volumeDown", 1)
打开、停止App
打开APP
s = c.session('com.apple.Health') # 打开app
s = c.session('com.apple.Health', alert_action="accept")
s.close() # 关闭
c.session().app_activate("com.apple.Health") # 打开app
停止APP:
c.session().app_terminate("com.apple.Health") # 关闭app
获取app状态:
>>> c.session().app_state("com.apple.Health") # 返回app状态
{'value': 1, 'sessionId': 'BEB6A59E-254A-428A-AB53-F52A957ABE1F', 'status': 0}
1
:表示已关闭2
:表示后台运行4
:表示正在运行
获取设备应用信息
查看设备状态信息
>>> c.status()
{'message': 'WebDriverAgent is ready to accept commands', 'state': 'success', 'os': {'testmanagerdVersion': 28, 'name': 'iOS', 'sdkVersion': '14.5', 'version': '14.6'}, 'ios': {'ip': '192.168.5.159'}, 'ready': True, 'build': {'time': 'Jul 27 2021 20:50:24', 'productBundleIdentifier': 'com.facebook.WebDriverAgentRunner'}, 'sessionId': '4D60BDFB-5D18-4EFB-8C40-97E4826B9AAB'}
获取应用信息
当前应用信息
>>> c.app_current()
{'processArguments': {'env': {}, 'args': []}, 'name': '', 'pid': 228, 'bundleId': 'com.apple.Preferences'}
获取设备信息
设备信息
>>> c.device_info()
{'timeZone': 'GMT+0800', 'currentLocale': 'zh_CN', 'model': 'iPhone', 'uuid': '1DF5DFF9-93B2-4B87-8249-DB33ADB6A330', 'userInterfaceIdiom': 0, 'userInterfaceStyle': 'light', 'name': 'iPhone12', 'isSimulator': False}
>>>
电量信息
>>> c.battery_info()
{'level': 0.9800000190734863, 'state': 2}
分辨率:
>>> c.window_size()
Size(width=375, height=812)
UI元素定位
基本选择器
通过属性值定位:
id
s(id='URL')
className
s(className="XCUIElementTypeCell")
name
s(name='屏幕使用时间')
s(nameContains='屏幕')
s(nameMatches="屏幕.*")
value
s(value="屏幕使用时间")
label
s(label="屏幕使用时间")
s(labelContains="屏幕")
也可以组合多个属性,可以组合的属性包括:className、name、label、visible、enabled。
s(className="XCUIElementTypeCell",name="屏幕使用时间").click()
子元素
# 子元素定位
s(className='XCUIElementTypeTable').child(name='通知').exists
多个实例
返回所有匹配到的元素
$ s(nameContains='模式').find_elements()
[<wda.Element(id="15000000-0000-0000-0901-000000000000")>, <wda.Element(id="1B000000-0000-0000-0901-000000000000")>, <wda.Element(id="5E000000-0000-0000-0901-000000000000")>]
使用index来选择匹配到的多个元素
s(nameContains='模式', index=2).click() # 点击匹配到的第3个元素
# 或者
s(nameContains='模式')[2].click()
XPath定位
s(xpath='//*[@name="屏幕使用时间"]')
# 或者
s.xpath('//*[@name="屏幕使用时间"]')
更多xpath语法可参考Web自动化测试:xpath & CSS Selector定位
Predicate定位
Predicate定位是iOS原生支持的定位方式,定位速度比较快,它可以通过使用多个匹配条件来准确定位某一个或某一组元素。
s(predicate='name BEGINSWITH "屏幕"').click() # 点击屏幕使用时间
更详细的Predicate语法及定位示例可参考:iOS APP自动化:predicate定位
classChain定位
classChain是Predicate和Xpath定位的结合,搜索效率比XPath更高。
s(classChain='**/XCUIElementTypeTable/*[`name == "通知"`]').click() # 点击【通知】
更详细的使用方法参考:iOS APP自动化:class chain定位方法
获取元素信息
检查元素是否存在
s(name="屏幕使用时间").exists # Return True or False
读取UI元素的属性信息
ele = s(name="屏幕使用时间").get(timeout=3.0) # 如果10s内没有找到,会抛出WDAElementNotFoundError错误
ele = s(name="屏幕使用时间").wait(timeout=3.0)
# 获取元素属性
ele.className # XCUIElementTypeCell
ele.name # XCUIElementTypeCell
ele.visible # True
ele.value
ele.label # 屏幕使用时间
ele.text # 屏幕使用时间
ele.enabled # True
ele.displayed # True
ele.accessible
x, y, w, h = ele.bounds # Rect(x=0, y=744, width=375, height=46)
元素操作方法
点击
点击UI元素
s(name="屏幕使用时间").get(timeout=3.0).tap()
s(name="屏幕使用时间").tap()
s(name="设置").tap_hold(2.0) # 长按
s(name="屏幕使用时间").click()
s(text='屏幕使用时间').click_exists() # return True or False
s(text='屏幕使用时间').click_exists(timeout=5.0)
点击像素坐标
s = c.session('com.apple.Preferences')
s.tap(490, 1885) # 通过像素坐标点击
s.click(490, 1885)
s.click(0.426, 0.716)
s.double_tap(490, 1885) # 双击
文本输入
文本值输入与清除
ele = s(text='搜索').get()
ele.set_text("NFC") # 输入文本
ele.clear_text() # 清除文本
ele.set_text("\b\b\b\n") # 删除3个字符
ele.set_text("NFC\n") # 输入文本并确认
等待wait
设置隐式等待:
s.implicitly_wait(5) # 5s
设置超时时间
s.set_timeout(10.0)
等待元素
s(name="屏幕使用时间").wait(timeout=3.0) # 等待元素出现
s(name="屏幕使用时间").wait_gone(timeout=3.0) # 等待元素消失
Alert操作
对Alert弹框进行处理
>>> print(s.alert.exists)
True
>>> print(s.alert.text)
移除“设置”?
“从主屏幕移除”会将App保留在App资源库中。
s.alert.accept() # 确认
s.alert.dismiss() # 取消
s.alert.wait(5) # 等待出现
s.alert.buttons() # 返回选项,例如:['取消', '从主屏幕移除']
s.alert.click("取消") # 点击取消
s.alert.click(["取消", "cancel"]) # 点击出现的列表中的某个选项
也可以监控到Alert出现后进行操作:
with c.alert.watch_and_click(['好', '确定']):
s(label="Settings").click() #
滑动swipe
根据像素坐标滑动
c.swipe(fx, fy, tx, ty, duration=0.5) # 从(fx, fy)滑到(tx, ty),坐标值可以是迅速值或者百分比,duration单位秒
c.swipe_left() # 向左滑动
c.swipe_right()
c.swipe_up()
c.swipe_down()
截图
s.screenshot().save("test.png")
from PIL import Image
s.screenshot().transpose(Image.ROTATE_90).save("correct.png") # 横屏截图
设备截屏
c.screenshot().save("screen.png")
c.press_duration("snapshot", 0.1)
pytest + facebook-wda实例
测试步骤:
- 打开【设置】
- 点击搜索
- 输入“NFC”
- 关闭NFC
- 断言NFC是否关闭
Python代码:
#!/usr/bin/python3
# -*-coding:utf-8-*-
import wda
import time
wda.DEBUG = False # default False
wda.HTTP_TIMEOUT = 180.0 # default 180 seconds
wda.DEVICE_WAIT_TIMEOUT = 180.0
class TestDemo():
def setup(self):
self.c = wda.USBClient("00008101-000255021E08001E", port=8100)
self.c.wait_ready(timeout=300)
self.c.implicitly_wait(30.0)
def teardown(self):
self.c.session().app_terminate("com.apple.Preferences")
def test_NFC(self):
self.c.session('com.apple.Preferences')
self.c.swipe_down()
self.c(name="搜索").set_text("NFC") # 搜索 NFC
self.c(name="NFC").click() # 点击NFC
time.sleep(1)
ele = self.c(xpath='//Switch').wait(timeout=3.0)
sw = ele.value
if sw == '1':
ele.click()
self.c.alert.wait(3)
self.c.alert.click("关闭")
time.sleep(1)
sw = ele.value
assert sw == '0'
系列文章
1、Appium 介绍及环境安装
2、selenium/appium 等待方式介绍
3、App控件定位:Android 控件介绍及元素定位方法
4、Appium元素定位(一)
5、Appium元素定位(二):UiAutomator定位
6、Appium控件交互
7、Android WebView测试
8、AppCrawler自动遍历测试
9、自动遍历测试之Monkey工具
10、App自动化测试工具Uiautomator2
11、App自动化测试工具Airtest
12、Android手机管理平台搭建:STF和atxserver2
13、Windows上实现iOS APP自动化测试:tidevice + WDA + facebook-wda / appium
14、iOS APP自动化:predicate定位
15、iOS APP自动化:class chain定位方法
16、使用facebook-wda进行iOS APP自动化测试
![Logo](https://devpress.csdnimg.cn/79de2bf0b7994defa4242ef90d5513fa.jpg)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)