Airtest框架和Poco框架常见问题
Posted 测试界的飘柔
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Airtest框架和Poco框架常见问题相关的知识,希望对你有一定的参考价值。
Airtest
报告可以导出发给别人看吗
Airtest的报告是可以打包发给别人看的。
① 想要导出报告发给别人观看,我们需要生成报告的命令中传入 --export 参数,这样就可以将 包含静态资源文件和图片文件的报告 导出到一个指定的文件夹内,之后直接将整个文件夹发送给别人观看即可。
② 如果生成报告时不传入 --export 参数,那么报告中的静态资源文件和图片文件将使用 绝对路径 来访问,此时将整个文件夹发给别人观看,别人也是无法正常观看的。
如何在报告中显示报错信息
可以使用如下代码:
import traceback
try:
xxxx
except:
log("出错啦", traceback. format_exc())
如何取消脚本执行过程刷新大量的log信息
在脚本运行的时候, Airtest 默认会刷新很多log信息,如下图所示:
如果你不想这些log信息干扰你提取有效的报错信息时,你可以在脚本代码开头加上log级别的设定:
# -*- encoding=utf8 -*-
__author__ = "user"
import logging
logger = logging.getLogger("airtest")
logger.setLevel(logging.ERROR)
from airtest.core.api import *
auto_setup(__file__)
这样运行时只会在初始化手机时会有少量log输出,初始化完毕后就能够对logger进行过滤了。
用Airtest测试ios一定要用macOS吗
① 使用 xcode 部署 iOS-Tagent或WDA 需要在macOS完成
② 部署好以后可以在macOS或Windows机器上连接到iOS手机进行测试
如何删除iOS输入框的内容
① 对于android平台,我们可以使用多种方法来删除输入框的内容,比如使用 keyevent 接口:keyevent(“KEYCODE_DEL”) ;或者使用Poco的 set_text() 方法:poco(“xxx”).set_text(“”) ;
②但对于iOS平台来说,暂不支持 set_text() 接口,也不支持 keyevent(“KEYCODE_DEL”) ,所以这俩种方法对于iOS的输入框来说是无效的。而iOS是支持 text() 方法的,所以我们可以用 text(“\\b”,False) (每次删除1个字符,删除后不执行 enter ),来实现iOS输入框内容的删除。
自定义截图压缩精度
① 在本地运行脚本时自定义:
# quality取值[1,99],airtest默认取10,希望获得更高精度可以取值75
airtest run xxx --compress 75
② 在脚本中自定义(优先级高于在命令行自定义):
自定义全局的截图压缩精度:
import airtest.core.api import *
ST.SNAPSHOT_QUALITY = xxx
自定义单张截图的压缩精度:
snapshot(quality=my_quality)
Airtest支持多设备运行吗
…
输入密码时Airtest不显示密码键盘
脚本运行到输入密码时,手机弹出了安全键盘,但是在Airtest中却不显示这个安全键盘,这是为什么?
其实这个是正常现象,Airtest不会录制有安全键盘的画面,但是各种输入操作还是正常进行的。
Airtest如何局部截图、找图
Airtest局部截图+找图、截屏另存为
Airtest的多图查找
Airtest没有提供专门的API给我们进行多图查找,但是我们可以用简单的语法来实现:
picList = [pic1,pic2,pic3] # 截图的图片对象列表
for pic in picList:
pos = exists(pic)
if pos:
touch(pos)
break # 只要找到图片列表中的任何一张图片,就执行touch
invalid syntax
典型的python语法错误,常见于脚本未换行、缩进错误、缺少 " 或者 ( 等。
怎么点击软键盘上面的搜索?输入后回车?
如需点击软键盘上面的 search 按钮,则:
text("文本",enter=False,search=True)
同理,如需输入后回车,则 text(“文本”,enter=True) ,不需要回车则, text(“文本”,enter=False) 。
不能输入密码?密码界面黑屏?
应用的登录页面或者密码界面一般都不给截屏录屏的,同学们可以检查看看你的测试设备的设置里面,有没有安全键盘、防止恶意截屏录屏之类的设置,关掉就行。
如果是App本身做的安全机制,需要让开发打一个测试的包看能不能去掉。
‘NoneType’ object has no attribute xxxx
这个报错可能出现在不同的方法里面,比如:
AttributeError: 'NoneType' object has no attribute 'snapshot'
AttributeError: 'NoneType' object has no attribute 'start_app'
出现这些报错,基本上都是因为同学们在脚本中没有连接设备,所以只要在脚本开头,补充上连接设备的脚本即可。
Poco
poco无限重启的解决办法
如果开了网络代理的话,需要先 关闭各种代理和VPN ,否则可能会影响到poco通讯
检查手机助手内是否对 pocoservice.apk 做了限制,例如在某版本的华为手机中需要开启 允许自启动 和 允许后台活动。
这里我们列举几个常见手机品牌的设置方式:
华为:手机管家-应用启动管理-PocoService.apk-手动管理,允许自启动开启,允许后台活动开启
OPPO:设置-电池-应用耗电管理-PocoService.apk-允许应用自启动,允许完全后台行为
VIVO:电池-后台高耗电-> PocoService 开启
一加:设置-电池优化-PocoService-不优化
当然,不同手机品牌,甚至同品牌不同型号手机的配置方式,都有可能不大一样,同学们要自己查找手机里面与 电池优化 和 后台活跃 相关的设置即可,保证给 pocoservice.apk 足够的活跃权限且不被电池优化行为干掉。
不能和uiautomator同时启动,否则会相互冲突
可以尝试 重启手机 / 重装pocoservice 看看是否会恢复
poco拿不到控件,poco的支持情况
目前只有原生应用可以直接使用poco(无需接入pocoSDK),非原生应用,比如各种游戏应用、H5小程序、混合开发的应用等,都不能直接使用poco拿取控件,绝大多数的游戏支持接入对应引擎的pocoSDK之后,可以获取控件信息。
poco定位报错找不到
有时候IDE自动生成的poco定位脚本会非常长,层级也非常深,回放时可能出现找不到控件的情况;这时不建议同学们直接使用自动生成的定位脚本,可以根据UI树详情,另外编写更精简的定位脚本,推荐使用正则匹配来进行脚本定位会好一些。
如果定位脚本是同学们自己编写的,请检查对应的属性或者层级关系,看是否是脚本错误而导致找不到元素。
如出现单独选中调试脚本,可以找到控件,但实际运行脚本又容易找不到控件,建议在该条定位脚本之前添加足够的 sleep() ,确保画面跳转稳定后,再来查找控件。
“远程主机强迫关闭了一个现有的连接”、“socket connection broken”
很多新手在使用poco的时候,都容易把连接设备、初始化poco和打开应用的脚本顺序搞乱,导致出现一大堆奇妙的报错。
比如大家最常见的:“远程主机强迫关闭了一个现有的连接”、“socket connection broken” 等等。
最正确的顺序是:先连接设备(一般在 auto_setup 接口里面连接)–> 再打开应用(一般用 start_app 接口)–> 等应用开启完毕,最后才初始化 poco 。
# -*- encoding=utf8 -*-
__author__ = "Airtest"
from airtest.core.api import *
# 连接设备
auto_setup(__file__,logdir=True,devices=["Android://127.0.0.1:5037/emulator-5554?cap_method=JAVACAP"])
#启动应用
start_app("com.NetEase")
sleep(6.0)
# 初始化poco
from poco.drivers.unity3d import UnityPoco
poco = UnityPoco()
poco("btn_start").click()
所以同学们在初始化poco的时候,千万记住要检查下这几条代码的顺序,避免产生不必要的报错。
同一个脚本初始化多个poco(1个原生1个游戏)
在同一个脚本内,支持初始化多个不一样的poco,比如 Android poco 和 unity poco,就是可以共存的:
from airtest.core.api import *
auto_setup(__file__,devices=["android://127.0.0.1:5037/emulator-5554?cap_method=MINICAP_STREAM&&ori_method=MINICAPORI&&touch_method=MINITOUCH"])
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
A_poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)
sleep(1.0)
A_poco("poco").click()
sleep(2.0)
from poco.drivers.unity3d import UnityPoco
U_poco = UnityPoco()
U_poco("btn_start").click()
但是我们不能在同一个脚本内,反复初始化相同的poco,比如多次初始化Android poco,就有可能导致奇奇怪怪的错误出现。
资源分享
下方这份完整的软件测试视频学习教程已经上传CSDN官方认证的二维码,朋友们如果需要可以自行免费领取 【保证100%免费】
airtest图像识别+poco使用实践
airtest图像识别+poco使用实践
前言
最近在学习UI自动化,关于框架的挑选对我来说没啥好挑的,就airtest了,图像识别和接入poco-SDK,公司项目还没有接好SDK,拿网易的提供的demo先来练练手。
安装
我习惯使用python来跑自动化,有些库得安装下 1、airtest
pip install airtest
2、UI自动化框架:poco
pip install poco
3、测试框架:pocounit
pip install pocounit
4、Androiddemo下载链接:[1]
先上官网的例子
一、父类
from poco.drivers.unity3d import UnityPoco
from pocounit.case import PocoTestCase
from pocounit.addons.poco.action_tracking import ActionTracker
class MyBaseTestCase(PocoTestCase):
@classmethod
def setUpClass(cls):
super(MyBaseTestCase, cls).setUpClass()
cls.poco = UnityPoco()
# 启用动作捕捉(action tracker)
action_tracker = ActionTracker(cls.poco)
cls.register_addon(action_tracker)
二、测试用例(继承父类)
# 一个文件里建议就只有一个TestCase
# 一个Case做的事情尽量简单,不要把一大串操作都放到一起
class MyTestCase(MyBaseTestCase):
def setUp(self):
# 可以调用一些前置条件指令和预处理指令
pass
# 函数名就是这个,用其他名字无效
def runTest(self):
'''self.assertEqual相关的断言方法不会收集在测试报告中(网易那边不支持)
要用self.call_airtest.airtest_api.assert_equal相关方法才会收集在测试报告中
'''
# 普通语句跟原来一样
# self.poco(text='角色').click()
# 断言语句跟python unittest写法一模一样
# self.assertTrue(self.poco(text='最大生命').wait(3).exists(), "看到了最大生命")
# self.poco('btn_close').click()
# self.poco('movetouch_panel').offspring('point_img').swipe('up')
start_btn = self.poco('btn_start')
start_btn.click()
time.sleep(0.5)
self.assertEqual(start_btn.get_name(),'btn_start',msg='测试一下断言报告')
try:
self.assertEqual(start_btn.get_name(),'btn_start1',msg='测试一下断言报告 1')
except :pass
self.try_assert_mothod(self.assertEqual,start_btn.get_name(), 'btn_start1','测试一下断言报告 2')
basic_btn = self.poco(text='basic')
basic_btn.click([0.5,0.5])
self.try_assert_mothod(self.assertEqual,basic_btn.get_name(),'abc','测试一下断言报告 3')
back_button= self.poco('btn_back',type='Button').focus([1,0.1])
back_button.click()
if self.poco(text='drag drop').exists():
self.poco(text='drag drop').click()
else:
back_button.click()
def tearDown(self):
# 如果没有清场操作,这个函数就不用写出来
pass
# 不要写以test开头的函数,除非你知道会发生什么
# def test_xxx():
# pass
if __name__ in '__main__':
pocounit.main()
# generate html report
time_str = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
simple_report(__file__,output=REPORTPATH/f'test_{time_str}.html',logpath=str(LOGPATH))
实践poco+图像识别
一、封装断言方法
如果正常执行断言方法,失败的话后面的用例会被中断,所以得加上异常兼容;
1、poco的封装
def poco_assert_mothod(self,func,*args,case_msg=None):
'''
:param func: 断言方法
:param args: 断言方法里需要的参数
:return: 返回断言结果
'''
try:
if case_msg:
return func(*args,msg=case_msg)
else:
return func(*args)
except Exception as e:
print(f'{func} ERROR:', e)
return False
2、airtest图像识别的封装
def img_assert_mothod(self,func=None,img_1=None,img_2=None,case_msg='空白说明',threshold=0.8,target_pos=False,rgb=False):
'''
:param func: 断言方法,用加括号
:param args: 断言方法里需要的参数
:return: 返回断言结果
'''
'''
Template(r"tpl1532588127987.png", record_pos=(0.779, 0.382), resolution=(407, 264), threshold=0.6, target_pos=5, rgb=False)
threshold:识别精准度
target_pos:点击坐标偏移
rgb:色彩识别
示例:assert_not_exists(self.img_template(img), msg)
'''
def img_template(img):
if not target_pos:
return Template(self.img_path + img, threshold=threshold, resolution=self.screen_size, rgb=rgb)
else:
return Template(self.img_path + img, threshold=threshold, target_pos=target_pos, resolution=self.screen_size, rgb=rgb)
try:
if case_msg and img_1 and img_2:
return func(img_template(img_1),img_template(img_2),case_msg)
elif case_msg and (img_1 or img_2):
if img_1:
return func(img_template(img_1),case_msg)
elif img_2:
return func(img_template(img_2),case_msg)
elif case_msg is False:
return func(img_template(img_1))
except Exception as e:
print(f'{func} ERROR:', e)
二、给父类添加ADB的方法
class MyBaseTestCase(PocoTestCase):
@classmethod
def setUpClass(cls):
super(MyBaseTestCase, cls).setUpClass()
cls.poco = UnityPoco()
# 启用动作捕捉(action tracker)
action_tracker = ActionTracker(cls.poco)
cls.register_addon(action_tracker)
self.img_ath = None
# AdbShell在之前的的文章里可以找到,封装常用的adb命令
self.adb = AdbShell()
self.task_id = None
if self.check_devices():
self.screen_size = self.adb.get_screen_size()
# demo游戏包名
self.app_name = 'com.NetEase'
self.app = self.adb.get_thirdparty_app(filter=self.app_name)
else:raise ConnectionError
# 获取操作系统
self.system = os.name
def check_devices(self):
if self.adb.getDevices() is not False:
return True
else:
self.adb.adb('adb kill-server')
self.adb.adb('adb start-server')
三、poco常用方法
def __doc__(self):
'''选择UI对象'''
self.poco('')
# select by node name
self.poco('bg_mission')
# select by name and other properties
self.poco('bg_mission', type='Button')
self.poco(textMatches='^据点.*$', type='Button', enable=True) #加上对应属性来定位
# select by direct child/offspring
self.poco('main_node').child('list_item').offspring('item')
# 顺序选择
items = self.poco('main_node').child('list_item').offspring('item')
print(items[0].child('material_name').get_text())
# 迭代遍历一组UI
items = self.poco('main_node').child('list_item').offspring('item')
for item in items:
item.child('icn_item')
'''读取属性'''
mission_btn = self.poco('bg_mission')
print(mission_btn.attr('type')) # 'Button'
print(mission_btn.get_text()) # '获取text'
print(mission_btn.attr('text')) # equivalent to .get_text()
print(mission_btn.exists()) # True/False, exists in the screen or not
'''操作UI对象'''
# 点击
self.poco('bg_mission').click()
self.poco('bg_mission').click('center')
self.poco('bg_mission').click([0.5, 0.5]) # equivalent to center
self.poco('bg_mission').focus([0.5, 0.5]).click() # equivalent to above expression
self.poco()
# 滑动
joystick = self.poco('movetouch_panel').child('point_img')
joystick.swipe('up')
joystick.swipe([0.2, -0.2]) # swipe sqrt(0.08) unit distance at 45 degree angle up-and-right
joystick.swipe([0.2, -0.2], duration=0.5)
# 拖拽
self.poco(text='突破芯片').drag_to(self.poco(text='岩石司康饼'))
# 等待
self.poco('bg_mission').wait(5).click() # wait 5 seconds at most,click once the object appears
self.poco('bg_mission').wait(5).exists() # wait 5 seconds at most,return Exists or Not Exists
self.poco().wait_for_appearance() # 等待目标出现,超时raises PocoTargetTimeout
self.poco().wait_for_disappearance() # 等待目标消失,超时raises PocoTargetTimeout
# self.poco.wait_for_any()
# self.poco.wait_for_all()
'''全局操作'''
# 点击
self.poco.click([0.5, 0.5]) # click the center of screen
self.poco.long_click([0.5, 0.5], duration=3)
# swipe from A to B
point_a = [0.1, 0.1]
center = [0.5, 0.5]
self.poco.swipe(point_a, center)
# 滑动
direction = [0.1, 0]
self.poco.swipe(point_a, direction=direction)
# 截屏
from base64 import b64decode
b64img, fmt = self.poco.snapshot(width=720)
open('screen.{}'.format(fmt), 'wb').write(b64decode(b64img))
四、商店测试用例
SDK还没有接好,目前是用图像识别的方式写个demo
class TestShop(MyBaseTestCase):
'''
用例设计参考思维导图的测试用例
'''
def setUp(self):
self.call_airtest.img_path = Path(__file__).parent / 'imgFolder'
def close_tips(self):
tips_1 = self.call_airtest.img_assert_mothod(exists,'goods_tips_close_btn.png',case_msg=False)
tips_2 = self.call_airtest.img_assert_mothod(exists,'rank_close_btn.png',target_pos=3,case_msg=False)
if tips_1:
touch(tips_1)
if tips_2:
touch(tips_2)
def runTest(self):
self.close_tips()
'''用例执行方法在这里'''
self.entrance('shop_icon_1.png', 'shop_icon_2.png', 'shop_homepage.png')
self.shop_type('yuanbao_shop.png', 'duihuan_shop.png','jipin_shop.png','jifen_shop.png')
self.title('shop_tag_1.png','shop_tag_2.png','shop_tag_3.png')
# 购买多个商品,图片坐标偏移8
shop_goods_list = [
('银两','yinliang.png','yinliang_max.png',5),
('福袋碎片','fudai.png','fudai_max.png',1),
('5级宝石', 'baoshi5.png', 'baoshi5_max.png', 5),
('兽丹礼包', 'shoudan.png', 'shoudan_max.png', 5),
]
for test_data in shop_goods_list:
self.gold_daily_shop(*test_data)
def tearDown(self):
# 如果没有清场操作,这个函数就不用写出来
pass
# 判断入口
def entrance(self,enter_img_1=None,enter_img_2=None,shop_homepage=None):
shop_icon = self.call_airtest.img_assert_mothod(assert_exists,enter_img_1,case_msg='显示商店图标')
if shop_icon:
touch(shop_icon)
sleep(1.5)
self.call_airtest.img_assert_mothod(assert_exists,shop_homepage,case_msg='进入后出现商品页签')
else:
wait_shop_icon = wait(Template(self.call_airtest.img_path+enter_img_2),5)
if wait_shop_icon:
touch(wait_shop_icon)
self.call_airtest.img_assert_mothod(assert_exists,shop_homepage,case_msg='进入后出现商品主页')
else:
raise TargetNotFoundError
def shop_type(self,type_1,type_2,type_3,type_4):
'''各个商城'''
self.shop_type_1 = self.call_airtest.img_assert_mothod(assert_exists,type_1,case_msg='显示元宝商城')
self.shop_type_2 = self.call_airtest.img_assert_mothod(assert_exists,type_2,case_msg='显示兑换商城')
self.shop_type_3 = self.call_airtest.img_assert_mothod(assert_exists,type_3,case_msg='显示极品商城')
self.shop_type_4 = self.call_airtest.img_assert_mothod(assert_exists,type_4,case_msg='显示积分商城')
def title(self,shop_tag_1,shop_tag_2,shop_tag_3):
'''页签'''
self.shop_tag_1 = self.call_airtest.img_assert_mothod(assert_exists,shop_tag_1,case_msg='显示每日特惠页签')
self.shop_tag_2 = self.call_airtest.img_assert_mothod(assert_exists,shop_tag_2,case_msg='显示常用道具页签')
self.shop_tag_3 = self.call_airtest.img_assert_mothod(assert_exists,shop_tag_3,case_msg='显示特权商城页签')
def gold_daily_shop(self,goods,goods_img,goods_max_img,buy_max):
'''商店购买'''
# 点击元宝商城
if self.shop_type_1:
touch(self.shop_type_1)
# 点击每日特惠
if self.shop_tag_1:
touch(self.shop_tag_1)
else:
print('入口目标没有找到,调整截图或降低识别率')
raise TargetNotFoundError
# self.call_airtest.img_assert_mothod(assert_exists,cost_img,case_msg=f'{goods}道具价格')
# 商品
self.goods_pos = self.call_airtest.img_assert_mothod(assert_exists,goods_img,target_pos=8,case_msg=f'显示{goods}道具')
# swipe(self.goods_pos,vector=(0.5,0.8))
if self.goods_pos:
# 限购
for i in range(buy_max):
touch(self.goods_pos)
# 滑动到底部
# 滑动一次接近翻一页
self.swipe_up_pos = (520,1910),(520,607)
swipe(*self.swipe_up_pos)
swipe(*self.swipe_up_pos)
sleep(1)
self.goods_max_pos = self.call_airtest.img_assert_mothod(assert_exists,goods_max_img,case_msg=f'{goods}购买{buy_max}次后,达到上限灰化')
# 划回去
self.swipe_down_pos = (520,607),(520,1910)
swipe(*self.swipe_down_pos)
swipe(*self.swipe_down_pos)
sleep(1)
结语
UI自动化这块我接触的少,经验也不足,属于摸索起步阶段,据了解目前多数同行都应用于回归测试,向他们请教怎么应用,后续有好的应用方法再更新上来,有好的建议欢迎留言,感谢。
引用链接
[1]
下载链接:: http://top.gdl.netease.com/poco-res/poco-demo-unity-game-android.zip
以上是关于Airtest框架和Poco框架常见问题的主要内容,如果未能解决你的问题,请参考以下文章