四、Poco控件的核心API讲解
1. 前言
本文将以官网上的安卓游戏demo为例,下载地址。下载完对应的 “demo game android” 以后,安装在待测的安卓手机上,启动游戏;再使用IDE连接上待测手机,并在poco辅助窗选择 unity
模式,刷出UI树后即可开始测试。
阅读本文,你将了解poco控件的以下核心API功能:
- 点击操作
- 滑动操作
- 读取和设置控件的属性
- 判断元素是否存在
- 拖动操作
- 内部偏移和外部偏移(focus)
- 等待事件
2. 控件点击操作
目前poco控件的支持的点击操作包含单击和长按,双击和右键单击均未实现。
# 控件单击
poco("star_single").click()
# 控件长按
poco('star_single').long_click()
click()
和 long_click()
的API详情可以参看此链接:https://poco.readthedocs.io/zh\_CN/latest/source/poco.drivers.std.inputs.html?highlight=click#poco.drivers.std.inputs.StdInput.click 。
Poco控件的双击和右键点击
目前Poco控件的双击double_click()
和右键点击rclick()
方法均未实现,同学们在使用时,会报错提示:NotImplementedError
。
3. 控件的滑动操作
Poco支持对控件进行滑动操作,我们需要先定位到这个控件,然后指定它按照某个方向滑动即可:
# -*- encoding=utf8 -*-
__author__ = "AirtestProject"
from airtest.core.api import *
auto_setup(__file__)
from poco.drivers.unity3d import UnityPoco
poco = UnityPoco()
# 向下滑动0.2个单位距离
poco("Handle").swipe([0,0.2])
sleep(1.0)
# 向上滑动0.2个单位距离
poco("Handle").swipe([0,-0.2])
sleep(1.0)
# 向下滑动0.1个单位距离
poco("Handle").swipe("down")
sleep(1.0)
# 向上滑动0.1个单位距离
poco("Handle").swipe("up")
sleep(1.0)
控件滑动的API(swipe
)详情,可以参看此链接:https://poco.readthedocs.io/zh\_CN/latest/source/poco.proxy.html#poco.proxy.UIObjectProxy.swipe 。
4. 控件属性的读取和设置
1)控件属性的读取
我们在IDE的poco辅助窗检索出来的控件属性,基本上都可以通过 attr
接口读取出来:
# -*- encoding=utf8 -*-
__author__ = "AirtestProject"
from airtest.core.api import *
auto_setup(__file__)
from poco.drivers.unity3d import UnityPoco
poco = UnityPoco()
print("----------------")
print("name:"+poco("star_single").attr("name"))
print("type:"+poco("star_single").attr("type"))
print("texture:"+poco("star_single").attr("texture"))
attr
的详情可以参看此链接:https://poco.readthedocs.io/zh\_CN/latest/source/poco.proxy.html#poco.proxy.UIObjectProxy.attr 。
另外,Poco还支持使用特定的API获取控件的某一属性值:
- 获取控件的name属性:
get_name
- 获取控件的text属性:
get_text
- 获取控件的position属性:
get_position
- 获取控件的size属性:
get_size
- ……
# -*- encoding=utf8 -*-
__author__ = "AirtestProject"
from airtest.core.api import *
auto_setup(__file__)
from poco.drivers.unity3d import UnityPoco
poco = UnityPoco()
print("----------------")
print("name:"+poco("star_single").get_name())
print("position:"+str(poco("star_single").get_position()))
print("size:"+str(poco("star_single").get_size()))
此类API的详情,我们可以参看此链接的内容:https://poco.readthedocs.io/zh\_CN/latest/source/poco.proxy.html?highlight=get\_#poco.proxy.UIObjectProxy.get\_name 。
2)设置控件的属性值
通常我们需要设置元素属性的情况,就是设置文本框的文本属性(输入文本),可以使用 set_text()
方法或者 setattr()
方法:
# -*- encoding=utf8 -*-
__author__ = "AirtestProject"
from airtest.core.api import *
auto_setup(__file__)
from poco.drivers.unity3d import UnityPoco
poco = UnityPoco()
# 先激活输入光标
poco("pos_input").click()
# 再执行输入动作
poco("pos_input").set_text("123")
sleep(1.0)
poco("pos_input").setattr('text',"456")
这两方法的API详情可以参看此链接:https://poco.readthedocs.io/zh\_CN/latest/source/poco.proxy.html?highlight=set#poco.proxy.UIObjectProxy.set\_text 。
但如果我们强行设置不可修改的元素属性,就会报 InvalidOperationException
的错误:
5. 判断控件是否存在
判断控件是否存在,我们可以使用exists()
方法,它给我们返回的是布尔值,利用这一点,我们可以做很多应用。
1)控件存在则xx,不存在则yy
最常见的应用就是,如果控件存在,我们就点击它,否则就做别的操作,比如打印一条控件不存在的信息之类的:
if poco("star_single").exists():
poco("star_single").click()
else:
print("未找到星星控件")
区分Poco和Airtest的exists
Poco和Airtest框架都有一个exists
方法,但我们需要区分它们俩者的用法,Airtest的exists
是用于判断图片存在,exists(图片)
;而Poco的exists
是用于判断控件存在,poco(xxx).exists()
。
2)断言控件存在
利用控件存在返回的布尔值,我们可以巧妙地结合Airtest的断言相等,来断言控件存在:
assert_equal(poco("star_single").exists(),True,"断言星星控件存在")
exists
的方法详情,我们可以参考此链接的内容:https://poco.readthedocs.io/zh\_CN/latest/source/poco.proxy.html?highlight=exists#poco.proxy.UIObjectProxy.exists 。
6. 控件的拖动
控件的drag_to()
方法,终点可以是一个元素控件,也可以是一个固定的相对坐标:
# 拖动到另一个控件上
poco("playDragAndDrop").child("star")[0].drag_to(poco("shell"))
# 拖动到固定目标上
poco("playDragAndDrop").child("star")[1].drag_to([0.503, 0.705])
drag_to
的API详情,我们可以参考此链接的内容:https://poco.readthedocs.io/zh\_CN/latest/source/poco.proxy.html#poco.proxy.UIObjectProxy.drag\_to 。
7. 控件的内外部偏移
在之前的文档里面我们就提到过,poco使用的坐标系是 相对坐标系 。举个例子,我们选中下图的pearl图片控件,此时的坐标系就是相对这个控件的坐标系,并且是从0到1进行归一化的。
对这个控件进行点击操作,实际上点击的坐标是控件上(0.5,0.5)的位置:
poco(texture="icon").click()
1)内部偏移
如果选中控件之后,你并不想点击控件的中心位置,而是想点击控件内部的其它位置,我们可以使用 focus()
方法来指定内部偏移量:
# 内部偏移
pearl = poco(texture="icon")
pearl.focus('center').long_click()
sleep(1.0)
pearl.focus([0.1,0.1]).long_click()
sleep(1.0)
pearl.focus([0.9,0.9]).long_click()
2)外部偏移
选中1个控件以后,如果我们想点击控件之外的位置,也可以使用 focus()
方法来指定外部偏移量;并且会出现 点击坐标的值小于0或者大于1 的情况:
如上图所示,我们选中了 pearl 这个文本控件,但是我们想要去点击文本控件上方的图标,此时 focus
里面的Y坐标就是负数;因为相对于这个文本控件来说,上方图标的Y坐标已经小于0了:
# 外部偏移
pearl_text = poco(text="pearl")
pearl_text.focus([0.5,-3]).long_click()
同理,如果点击该文本控件正下方比较远的位置,Y坐标就有可能大于1;当Y坐标大到超出当前屏幕时,就会报错: InvalidOperationException('Click position out of screen.
。
focus()
方法的API详情可以参看此链接:https://poco-chinese.readthedocs.io/en/latest/source/poco.proxy.html?highlight=focus#poco.proxy.UIObjectProxy.focus 。
8. 控件的等待事件
1)仅等待不报错
我们可以使用wait
方法,指定时间等待控件出现,再进行点击操作(该方法的返回值是控件本身,所以后面可以紧跟控件操作,比如点击、长按):
# 在10s内等待控件出现,如出现,则进行长按操作
poco(texture="icon").wait(timeout=10).long_click()
wait
的API详情,可以参看此链接:https://poco.readthedocs.io/zh\_CN/latest/source/poco.proxy.html#poco.proxy.UIObjectProxy.wait 。
控件的wait方法
需要注意的是,Poco控件的wait
方法,即使在设定时间内未找到控件,也是不会报错的,可以继续往下执行下去。另外我们需要区分下Airtest的wait
方法,等待图片目标出现wait(图片)
;和Poco控件的wait
方法,等待控件出现poco(xxx).wait(timeout=3)
。
2)等待,不满足则报错
Poco控件还支持另外2个等待事件,wait_for_appearance()
和wait_for_disappearance()
;这两个API可以帮助我们等待页面上 某1个UI 出现或者消失,等待的超时时间 timeout
默认为120秒,如果在超时时长之内元素没有出现或者消失的话,会报 PocoTargetTimeout
的错误。
# 等待黄色小鱼出现
poco("yellow").wait_for_appearance(timeout=20)
# 等待计分文本控件消失
poco(text="Count:").wait_for_disappearance(timeout=3)
两个方法的API详情参考链接:https://poco-chinese.readthedocs.io/en/latest/source/poco.proxy.html?highlight=wait\_for\_appearance#poco.proxy.UIObjectProxy.wait\_for\_appearance 。
3)拓展:Poco类的等待事件
这里我们拓展一个Poco类的等待事件,wait_for_any()
和wait_for_all()
。与上述等待事件不同的是,wait_for_any()
和 wait_for_all()
可以给定多个UI对象让其等待。(需要注意这两个方法是Poco类的方法)
wait_for_all()
是在超时时长结束之前,需要 等待所有给定的UI对象都显示出来 ,即一次轮询所有UI,例如等待三个图标都显示之后,再点击返回按钮:
poco("wait_ui2").click()
yellow = poco("yellow")
blue = poco("blue")
black = poco("black")
poco.wait_for_all([yellow,blue,black])
poco("btn_back").click()
wait_for_any()
则是在超时时长结束之前,等待任意一个UI显示出来,即一次轮询任何一个给定的UI,例如:
bomb = poco("bomb")
yellow = poco("yellow")
blue = poco("blue")
while True:
fish = poco.wait_for_any([bomb,yellow,blue])
print(fish.get_name())
可以看到,只要页面出出现了等待的任一UI,wait_for_any()
方法都会返回第一个等待到的UI。
俩方法的API详情参考链接:https://poco-chinese.readthedocs.io/en/latest/source/poco.pocofw.html?highlight=wait\_for#poco.pocofw.Poco.wait\_for\_any 。
9. 遍历元素
通过python的for循环,我们可以 遍历任何序列的项目 ,如一个列表或者字符串。
举个例子,poco("playDragAndDrop").child("star")
得到的就是1个控件序列(包含了5个星星元素), star
代表控件序列中的1个元素。因此通过这个循环,我们就遍历了5个星星元素的序列,并把每个星星元素依次拖动到贝壳上:
for star in poco("playDragAndDrop").child("star"):
star.drag_to(poco("shell"))