宝藏工具Airtest,Unity自动化测试

Airtest Project是网易游戏内部工具团队开发并开源的一款UI自动化测试工具。

一、Airtest官网

http://airtest.netease.com/

二、Poco-SDK下载

https://github.com/AirtestProject/Poco-SDK

三、中文文档

https://airtest.doc.io.netease.com/#

四、Airtest 常用函数

1 获取屏幕尺寸

from poco.drivers.android.uiautomation import AndroidUiautomationPoco
android_poco= AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)
screen_with, screen_height = android_poco.get_screen_size()

2 引用其他air脚本

from airtest.core.api import using
using("other_test.air") # 需要使用相对路径,不然找不到.air
import other_test

3 元素定位

根据对象名字定位

login_btn = poco("login_btn")
# 按钮点击
login_btn.click()

根据文本内容来定位

login_btn = poco(text="账号登录")
login_btn.click()

用正则表达式来模糊定位

login_btn = poco(textMatches="^.*账号登录.*$")
login_btn.click()

子元素

list_item = poco('list_root').child('list_item')

父节点

poco('node_item').parent()

兄弟节点

poco('user_level').sibling('user_name')

4 点击元素身上的某一点:focus、click

通过相对坐标,控制点击的具体位置。左上角(0, 0),右下角(1, 1)

node = poco(text='领取奖励')
# 点击节点的中心点位置, 默认点击中心位置
node.focus('center').click()
# 点击节点的靠近左上角位置
node.focus([0.1, 0.1]).click()
# 点击节点的右下角位置
node.focus([0.9, 0.9]).click()

5 等待元素出现或消失:wait_for_appearance、wait_for_disappearance

当使用wait_for_appearancewait_for_disappearance时,建议处理PocoTargetTimeout,并截图,以方便在报告中查看出错时的页面情况

try:
	# 元素出现
    poco(text='领取奖励').wait_for_appearance(timeout=10)
    # 元素消失
    # poco(text='领取奖励').wait_for_disappearance(timeout=10)
except PocoTargetTimeout:
    snapshot(msg="超时: [领取奖励]元素出现")

6 拖动:drag_to

# 将star(星星)拖动到shell(贝壳)那里
poco('star').drag_to(poco('shell'))

7 滑动:swipe

 # 滑动指定坐标
poco('Scroll View').swipe([0, -0.1]) 
# 向上滑动
poco('Scroll View').swipe('up')  
# 向下滑动
poco('Scroll View').swipe('down')  

封装,水平滑动和垂直滑动,把不在屏幕内部的控件滑动到屏幕内,使之可被操作

#先计算屏幕宽和高
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
android_poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)
screen_width, screen_height = android_poco.get_screen_size()


'''
水平滑动,把不在屏幕内部的控件滑动到屏幕内,使之可被操作
:param element: 控件元素
:param area_left: 希望控件所在屏幕上的区域的左边缘:0~1
:param area_right: 希望控件所在屏幕上的区域的右边缘:0~1
:param swipe_pos_y: 滑动时点击的y坐标
'''
def horizontal_swipe_element_to_area(element, area_left=0.3, area_right=0.7, swipe_pos_y=320):
    swipe_pos_x = (area_left+area_right)*0.5*screen_width
    for i in range(50):
        cur_pos = element.get_position()
        cur_pos_x = cur_pos[0]
        if cur_pos_x < area_left or cur_pos_x > area_right:
            #如果在区域左边,则往右滑,如果在区域右边,则往左滑
            swipe([swipe_pos_x ,swipe_pos_y], [2*swipe_pos_x -cur_pos_x*screen_width, swipe_pos_y])
        else:
            print("swipe finish")
            break


'''
垂直滑动,把不在屏幕内部的控件滑动到屏幕内,使之可被操作
:param element: 控件元素
:param area_top: 希望控件所在屏幕上的区域的上边缘:0~1
:param area_bottom: 希望控件所在屏幕上的区域的下边缘:0~1
:param swipe_pos_x: 滑动时点击的x坐标
'''
def vertical_swipe_element_to_area(element, swipe_pos_x=600, area_top=0.3, area_bottom=0.7):
    swipe_pos_y = (area_bottom+area_top)*0.5*screen_height
    for i in range(50):
        cur_pos = element.get_position()
        cur_pos_y = cur_pos[1]
        if cur_pos_y < area_top or cur_pos_y > area_bottom:
            #如果在区域上边,则往下滑,如果在区域下边,则往上滑
            swipe([swipe_pos_x,swipe_pos_y],[swipe_pos_x, 2*swipe_pos_y -cur_pos_y*screen_height])
        else:
            print("swipe finish")
            break
            

8 连续滑动:swipe_along

# 获取当前手机设备
dev = device() 
# 手指按照顺序依次滑过3个坐标
dev.minitouch.swipe_along([(100, 100), (200, 200), (300, 300)])

9 按住n秒拖动: hold、to

# 点击ui1保持1秒,拖动到ui2并保持1秒,然后抬起
ui1.start_gesture().hold(1).to(ui2).hold(1).up()

10 长按:long_click

# 长按,单位:秒
poco(text="长按").long_click(duration=2.0)

11 判断元素是否存在:exists

login_btn = poco(text="账号登录")
if login_btn.exists():
	login_btn.click()

12 UI状态清除:invalidate

poco里选择出来的UI都是代理对象,在执行同一个用例里,一个UI控件选出来后能持续多长时间有效这个是要看Android那回收UI资源的策略的,每个厂商的差异比较大。
对于cocos2d-x引擎的poco,由于使用的是快照模式,获取到UI状态后如果UI状态确实发生了改变,需要调用invalidate()进行重新获取。

btn = poco(text="领取奖励")
btn.click()

# 过了一段时间之后,再执行的时候,先调用invalidate进行重新获取代理对象
btn.invalidate()
btn.click()

13 两指挤压收缩操作:pinch

# 在给定的范围和持续时间下,在UI上两指挤压收缩操作
poco.pinch(direction='in', percent=0.6, duration=2.0, dead_zone=0.1)

14 无效的操作异常:InvalidOperationException

from poco.exceptions import *

try:
	# 点击屏幕外部,此时一定为报错,捕获到InvalidOperationException
    poco.click([1.1, 1.1])
except InvalidOperationException:
    snapshot(msg="无效的操作")

15 节点或属性不存在异常:PocoNoSuchNodeException

from poco.exceptions import *
node = poco("not existed node")
try:
    node.click()
except PocoNoSuchNodeException:
    snapshot(msg="节点不存在")

try:
    node.attr('text')
except PocoNoSuchNodeException:
    snapshot(msg="属性不存在")

16 等待超时异常:PocoTargetTimeout

from poco.exceptions import *
try:
    poco("login_btn").wait_for_appearance(timeout=10)
except PocoTargetTimeout:
    snapshot(msg="login_btn 等待超时")

17 对象已被清除:PocoTargetRemovedException

from poco.exceptions import *
try:
    poco('login_btn').click()
except PocoTargetRemovedException:
    snapshot(msg='login_btn 对象已被清除')

五、自定义poco属性

有时候,我们可能需要自定义一些属性,方便在poco中操作,比如自定义一个selfdefineAttr属性,
只需在PocoSDK中的UnityNode.cs添加想要的定义即可

public override object getAttr(string attrName)
{
    
    
	switch(attrName)
	{
    
    
		case "selfdefineAttr":
			return "Hello selfdefineAttr";
	}
}

另外,如果想在Poco渲染树中显示该属性,则在GetPayload()函数中添加字段即可

private Dictionary<string, object> GetPayload()
{
    
    
	Dictionary<string, object> payload = new Dictionary<string, object>() {
    
    
		{
    
    "selfdefineAttr", "Hello selfdefineAttr"}
	};
}

最后,我们就可以在Airtest中通过pocoattr方法获取到我们自定义的属性了

selfdefineAttr = poco('testNode').attr('selfdefineAttr')
print(selfdefineAttr)

猜你喜欢

转载自blog.csdn.net/linxinfa/article/details/107840992