python-自动化Airtest-3IDE poco介绍
python-自动化Airtest-3IDE poco介绍
一 : AirTest Poco 介绍
1> Poco 理解
Airtest:基于Python的、跨平台的UI自动化测试框架,基于图像识别原理,适用于游戏和App。
Poco:基于UI控件搜索的自动化测试框架,其核心优势是除了对Android、IOS之外,对游戏也是支持的,同时也支持微信小程序、微信小游戏和H5应用
部件 | 优点 |
---|---|
AirTest | 简单直接、兼容各种环境、无需嵌入代码 |
Poco | 控件识别更加准确、界面迭代影响小 |
2> Poco 安装
在python中要通过pip安装
pip install pocoui
在Airtest IDE 环境自带poco库
AirtestIDE\poco
3> Poco import
导入Poco 库
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
实例化
poco = AndroidUiautomationPoco(use_airtest_input=True,screenshot_each_action=False)
4> AirTest IDE Poco 介绍
在IDE 窗口上选择 Poco Assistant ;Poco 辅助窗口便在界面上显示
勾选需要链接设备类型;
这里选择android ,按照提示导入配置,及import 相关库和实例化Poco;
第一次链接设备安装 pocoservices apk完成界面即可获取到设备上的UI元素信息;
即在python 还是ide上可运行调试实现效果
demo
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)
# script content
print("start...")
poco(text="微信").long_click()
二: Poco 语法
1> Poco 获取信息
1. poco.adb_client
链接指定设备
from airtest.core.android import Android
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
dev1 = Android("27QGL20828000064")
poco = AndroidUiautomationPoco(dev1, screenshot_each_action=False)
链接设备默认
from airtest.core.api import *
from airtest.cli.parser import cli_setup
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)
class AndroidUiautomationPoco(Poco)
ef __init__(self, device=None, using_proxy=True, force_restart=False, use_airtest_input=False, **options):
# 加这个参数为了不在最新的pocounit方案中每步都截图
self.screenshot_each_action = True
if options.get('screenshot_each_action') is False:
self.screenshot_each_action = False
self.device = device or current_device()
if not self.device:
self.device = connect_device("Android:///")
self.adb_client = self.device.adb
有此处看adb_client 是当前链接设备,这里仍可调用许多方法;一般我们都会适用Poco直接调用方法
例如:
1, 获取当前设备号信息
print(poco.adb_client.devices())
========================
[('27QGL20828000064', 'device')]
2, adb.exe 路径信息
print(poco.adb_client.adb_path)
========================
D:\python373\lib\site-packages\airtest\core\android\static\adb\windows\adb.exe
3, 当前cpu 频率
print(poco.adb_client.get_cpufreq()
=========================
1.4GHz
4, ip 信息
print(poco.adb_client.get_ip_address())
=============================
192.168.16.104
5, 列出安装的apk
print(poco.adb_client.list_app())
============================
['com.github.uiautomator', 'com.android.cts.priv.ctsshim', 'com.huawei.camera', 'com.google.android.ext.services', 'com.huawei.android.launcher', ........
6, 获取屏幕的分辨率
# 获取屏幕当前的分辨率
w,h=device().get_current_resolution()
print(w,h)
#获取手机分辨率
w,h=poco.get_screen_size()
print(w,h)
7,正则表达式定位元素
nameMatches & textMatches
# 获取元素name属性 get_name()
print(poco(text='无线和网络').get_name() )
# 模糊匹配查询
print(poco(textMatches='.*?网络').get_name() )
=======================
android:id/title
8, 组合获取元素信息
获取信息:
获取位置:get_position()----》[0.25972222222222224, 0.27152777777777776]
获取元素边缘信息:get_bounds()-----》[0.25729166666666664, 0.36388888888888893, 0.2857638888888889, 0.15555555555555556]
获取元素name: get_name()---->android:id/title
获取元素text: get_text()----> 无线和网络
获取元素size: get_size()---->[0.20833333333333334, 0.02847222222222222]
2. poco.agent
class Poco(PocoAccelerationMixin):
...........
@property
def agent(self):
"""
Readonly property to access poco agent instance. See :py:class:`poco.agent.PocoAgent` for more details.
Returns:
:py:class:`poco.agent.PocoAgent`: poco agent instance
"""
return self._agent
返回:
py:类:“poco.agent。 PocoAgent: poco代理实例
print(poco.agent.screen.getPortSize())
print(poco.get_screen_size())
=========================
[720, 1440] # 屏幕分辨率
3. poco.device
poco.device.list_app() # 列出apk名
poco.device.get_ip_address() #获取ip 地址
4. poco.attr
例如:获取如下demo 信息;
获取参数:
visible:用户是否可见 ,返回布尔值;
text : 返回UI元素的字符串值
type:返回远程运行时UI元素的类型名
pos: 返回UI元素的位置
size:返回尺寸百分比[宽度,高度],根据屏幕显示0~1
name:返回UI元素的名称
… :返回SDK实现的其他属性
icon=poco(text="无线和网络")
print('UI元素的名称 {}'.format(icon.attr('name')))
print('用户是否可见 {}'.format(icon.attr('visible')))
print('UI元素的字符串值 {}'.format(icon.attr('text')))
print('运行时UI元素的类型名 {}'.format(icon.attr('type')))
print('UI元素的位置 {}'.format(icon.attr('pos')))
print('尺寸百分比[宽度,高度] {}'.format(icon.attr('size')))
print('其他属性信息 {}'.format(icon.attr('...')))
=======================================
UI元素的名称 android:id/title
用户是否可见 True
UI元素的字符串值 无线和网络
运行时UI元素的类型名 android.widget.TextView
UI元素的位置 [0.25972222222222224, 0.27152777777777776]
尺寸百分比[宽度,高度] [0.20833333333333334, 0.02847222222222222]
其他信息 None
后面可以对返回信息进行处理:
demo
w,h=device().get_current_resolution()#获取手机分辨率
icon=poco(text=“无线和网络”)
print(icon.attr(‘pos’))
x = int(icon.attr(‘pos’)[0]*w)
y = int(icon.attr(‘pos’)[1]*h)
print(x,y)
touch([x,y])
===================
[0.25972222222222224, 0.27152777777777776]
187 390
可以处理当前设备上坐标信息
2> Poco 模拟操作
1. poco.click()
在上节已经做介绍,这里可以对UI元素进行精确的锁定
poco.click()
if poco(text=’允许’).exists:
poco(text=’允许’).click()
2. poco.long_click()
参数:
pos: 按下坐标
duration 按下时间
def long_click(self, pos, duration=2.0):
下面这里可以对UI元素进行精确的锁定
poco(text="微信").long_click()
poco(text="设置").long_click(duration=3)
3. poco.scroll()
参数:滚动方向vertical &horizontal
percent: 滑动百分比
duration = 滑动时间float格式duration =3.0
def scroll(self, direction='vertical', percent=0.6, duration=2.0)
对屏幕的滚动控制
poco.scroll(direction='horizontal', duration=2,percent=0.8) #向左水平滑动
其实scroll 也是 通过swipe 来实现的操作
start = [0.5, 0.5]
half_distance = percent / 2
if direction == 'vertical':
start[1] += half_distance
direction = [0, -percent]
else:
start[0] += half_distance
direction = [-percent, 0]
return self.swipe(start, direction=direction, duration=duration)
4. poco.swipe()
参数:
direction : 方向,“上”,“下”,“左”,“右”-‘up’, ‘down’, ‘left’, ‘right’;
duration :操作执行的时间间隔
Raises: 当找不到元素时,会报错,raise PocoNoSuchNodeException(self)
def swipe(self, direction, focus=None, duration=0.5):
.........
ret = self.poco.swipe(origin, direction=dir_vec, duration=duration)
self.poco.post_action('swipe', self, (origin, dir_vec))
return ret
poco(text="显示").swipe('up')
poco(text="显示").swipe('down')
poco(text="设置").swipe('left')
5. poco.drag_to()
#把“设置”元素拖动到“ATX”元素上(拖拽)
参数:
target :参数的目标,
duration :操作执行的时间间隔
Raises: 当找不到元素时,会报错,raise PocoNoSuchNodeException(self)
def drag_to(self, target, duration=2.0)
poco(text='设置').drag_to(poco(text='ATX'),duration=3.0)
6. poco.start_gesture()
建序列化的手势动作
这里实现效果要比drag_to 好;
注意::总是在当前UI对象的位置开始触降
from airtest.core.api import *
from airtest.cli.parser import cli_setup
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)
ui11=poco(text="设置")
ui12=poco(text="手电筒")
ui13=poco(text="服务")
ui11.start_gesture().hold(1).to(ui12).hold(1).to(ui13).hold(1).up()
7. swipe_along()
调用 :touch_proxy.swipe_along()
建序列化的手势动作 作用和drag_to 、start_gesture一致;其对以上补充,可传参坐标list 进行制作滑动 手势;
参数:
coordinates_list:坐标列表,例如:[[250, 500],[300, 500],[300, 700],[600,700 ]]
duration :两个坐标间间隔时间
steps:执行每2个点之间的运行步数;当 解锁九宫格每一步没必要再拆分,所以steps设为1
可通过实际情况对参数传参控制时间间隔等信息;
def swipe_along(self, coordinates_list, duration=0.8, steps=5):
pos_list = [self.ori_transformer(xy) for xy in coordinates_list]
self.base_touch.swipe_along(pos_list, duration=duration, steps=steps)
demo
from airtest.core.api import *
dev = device()
dev.touch_proxy.swipe_along([[250, 500],[300, 500],[300, 700],[600,700 ]], duration=3, steps=3)
8. pinch()
上章对此功能在airtest做了解释,这里来说下的是poco 功能pinch他同样两指操作的
双指操作
poco(“无线和网络”).pinch()
def pinch(self, direction='in', percent=0.6, duration=2.0, dead_zone=0.1):
direction:缩放方向,只有"in"或"out"。 "in"表示挤压,"out"表示扩张
percent:从UI的边界压缩范围或扩大范围
duration:操作执行的时间间隔 obj: ' float
dead_zone:收缩内圆半径。 不应该大于' percent ' '
实现双指操作的还有如下touch_proxy.two_finger_swipe()
参数:
tuple_from_xy:开始坐标
tuple_to_xy:结束坐标
duration:时间间隔,默认0.8秒
steps:执行步数,默认5
offset:第二根手指偏移量,默认(0, 50)
其具体步骤:
swipe_events:滑动事件列表分别加入两根手指的按下事件;向滑动事件列表依次加入等待事件、两根手指的分段移动事件;追加两个手指的抬起事件
self.perform(swipe_events):将滑动事件列表中的每个事件依次执行
def two_finger_swipe(self, tuple_from_xy, tuple_to_xy, duration=0.8, steps=5, offset=(0, 50)):
tuple_from_xy = self.ori_transformer(tuple_from_xy)
tuple_to_xy = self.ori_transformer(tuple_to_xy)
self.base_touch.two_finger_swipe(tuple_from_xy, tuple_to_xy, duration=duration, steps=steps, offset=offset)
demo
from airtest.core.api import *
dev = device()
# 画两条竖向平行线 - 从[250, 550]到[250, 700],持续10秒,分5步,第2根手指偏移量(200,0)
dev.touch_proxy.two_finger_swipe([250, 550],[250, 700], duration=10, steps=5, offset=(200, 0))
#画两条横向平行线 - 从[150, 1000]到[700, 1000],其余参数全部用默认
dev.touch_proxy.two_finger_swipe([150, 1000],[700, 1000])
9. focus().click()
点击操作
poco(text='无线和网络').focus('center').click() # click the center
10. focus().drag_to()
scroll 操作
将 focus 和 drag_to 结合使用还能产生卷动(scroll)的效果
实现效果是局部的,是在poco(text=‘无线和网络’) 基础上移动相对图标高度的y值;
scrollView = poco(text='无线和网络')
scrollView.focus([0.5, 0.8]).drag_to(scrollView.focus([0.5, 0.1]))
注意:
如果实现大面积滑动时,就要选择元素的区域H足够高即如下;
scrollView = poco(name='android.widget.FrameLayout')
scrollView.focus([0.5, 0.8]).drag_to(scrollView.focus([0.5, 0.1]))
11. poco.pan()
平移
此功能未实现,可根据自己需求重新用swipe 封装使用
def pan(self, direction, duration=2.0):
raise NotImplementedError
3> 判断UI元素出现
1. 等待UI元素出现
poco等待UI元素的方式有三种:等待一个元素,等待多个元素,等待任一元素
poco.wait_for_all()
poco.wait_for_any()
poco.wait_stable()
#定位三个元素
ele1 = poco(text=“QQ”)
ele2 = poco(text=“QQ音乐”)
ele3 = poco(text=“微信”)
等待一个元素出现:ele1.wait_for_appearance(timeout=10)
等待多个元素都出现:poco.wait_for_all([ele1,ele2,ele3])
等待任一元素出现:poco.wait_for_any([ele1,ele2,ele3])
2. poco.wait_for_appearance()
poco阻塞并等待 wait_for_appearance
参数:
timeout :默认等待120s;阻塞并等待,直到UI元素在给定的超时内出现
PocoTargetTimeout:当超时
def wait_for_appearance(self, timeout=120)
eg:
poco(text='设置').wait_for_appearance()
3. 找不到元素就判断失败
result=poco(text="无线和网络").wait(5).exists()
print(result)
====================
True
4> 获取UI信息
通过Airtest 复制ui_path code 可以准确获取text 对应元素;
for pname in poco("android.widget.FrameLayout").offspring("com.android.settings:id/content_frame").offspring("com.android.settings:id/main_content").offspring("com.android.settings:id/dashboard_container").child("com.android.settings:id/dashboard_tile")[2].offspring("android:id/title"):
print(pname.get_text())
1. 相对选择器
直接查询其节点及子节点信息
offspring:包括直接子元素(ren)的子代
si = poco("android.widget.FrameLayout").offspring("com.android.settings:id/drawer_layout").attr('size')
print(si)
=====================================================
[1, 0.9430555555555555]
si = poco("android.widget.FrameLayout").offspring("com.android.settings:id/drawer_layout").children()
for i in si:
print(i.attr('name'))
===============
com.android.settings:id/content_parent
com.android.settings:id/content_parent
2. 获取父节点、子节点
获取home界面图标text 信息,无需在乎父节点上面是是什么,只需要能区分别的父节点UI元素即可;
data = poco("com.huawei.android.launcher:id/workspace_screen").child("android.view.ViewGroup").children()
for each in data:
print(each.get_text())
========================
服务
主题
CHH_pro
Yosemite
手电筒
ATX
时钟
设置
PocoService
Appium Settings
暴风影音
acount_app
3. 在子节点下-返回上级或多级父节点
获取text = ‘无线和网络’ 即0 节点的父节;
其父节点为1,2,3;android:id/icon;android.widget.RelativeLayout;com.android.settings:id/arrow
在往上为1,2,3 父节点: 4 -com.android.settings:id/dashboard_tile
demo
icon=poco(text="无线和网络").parent()
icon2=icon.sibling()
for i in icon2:
print('设置图标节点name值:{},size值: {}'.format(i.attr('name'), i.attr('size')))
==========================================
设置图标节点name值:android:id/icon,size值: [0.06666666666666667, 0.03333333333333333]
设置图标节点name值:com.android.settings:id/dashboard_tile,size值: [1, 0.07847222222222222]
设置图标节点name值:android.widget.RelativeLayout,size值: [0.7555555555555555, 0.07847222222222222]
设置图标节点name值:com.android.settings:id/arrow,size值: [0.044444444444444446, 0.03333333333333333]
size: 其中size 返回的是占据屏幕宽度、高度的百分比; 例如:[1, 0.07847222222222222],元素占据整个屏幕宽和高的0.07847222222222222;
注意:
如果要获取更上层父节点的话,需要在对象后添加继续添加parent()参数;相对与上面demo ;
寻找0节点的父节点;
icon=poco(text="无线和网络").parent().parent()
========================================
设置图标节点name值:com.android.settings:id/search_view_container,size值: [1, 0.05555555555555555]
设置图标节点name值:com.android.settings:id/dashboard_tile,size值: [1, 0.07847222222222222]
设置图标节点name值:com.android.settings:id/category,size值: [1, 0.011111111111111112]
设置图标节点name值:com.android.settings:id/dashboard_tile,size值: [1, 0.07847222222222222]
设置图标节点name值:com.android.settings:id/dashboard_tile,size值: [1, 0.07847222222222222]
设置图标节点name值:com.android.settings:id/dashboard_tile,size值: [1, 0.07847222222222222]
设置图标节点name值:com.android.settings:id/dashboard_tile,size值: [1, 0.07847222222222222]
设置图标节点name值:com.android.settings:id/dashboard_container,size值: [1, 0.8430555555555556]
设置图标节点name值:com.android.settings:id/dashboard_tile,size值: [1, 0.07847222222222222]
设置图标节点name值:com.android.settings:id/dashboard_tile,size值: [1, 0.07847222222222222]
设置图标节点name值:com.android.settings:id/dashboard_tile,size值: [1, 0.07847222222222222]
设置图标节点name值:com.android.settings:id/dashboard_tile,size值: [1, 0.07847222222222222]
设置图标节点name值:com.android.settings:id/dashboard_tile,size值: [1, 0.07013888888888889]
上两级父节点:com.android.settings:id/** 1,2 部分
上三级父节点:om.android.settings:id/dashboard_container 3部分
4. 空间顺序选择
child 当前节点的子元素
name_list=list(poco("android.view.ViewGroup").child())
print(len(name_list))
for i in range(len(name_list)):
print(poco("android.view.ViewGroup").child()[i])
print(poco("android.view.ViewGroup").child()[i].attr('text'))
print('='.center(90,"="))
name1=poco("android.view.ViewGroup").child()[0].attr('text')
print(name1)
========================
9
UIObjectProxy of "android.view.ViewGroup/[0]"
手机管家
UIObjectProxy of "android.view.ViewGroup/[1]"
None
UIObjectProxy of "android.view.ViewGroup/[2]"
图库
UIObjectProxy of "android.view.ViewGroup/[3]"
钱包
UIObjectProxy of "android.view.ViewGroup/[4]"
应用市场
UIObjectProxy of "android.view.ViewGroup/[5]"
None
UIObjectProxy of "android.view.ViewGroup/[6]"
None
UIObjectProxy of "android.view.ViewGroup/[7]"
None
UIObjectProxy of "android.view.ViewGroup/[8]"
None
==========================================================================================
手机管家
三: Airtest log
python-自动化Airtest-4 log介绍
https://blog.csdn.net/weixin_42914706/article/details/125590504