备注:未经博主允许禁止转载
个人笔记(整理不易,有帮助,收藏+点赞+评论,爱你们!!!你的支持是我写作的动力)
笔记目录:学习笔记目录_pytest和unittest、airtest_weixin_42717928的博客-CSDN博客
个人随笔:工作总结随笔_8、以前工作中都接触过哪些类型的测试文档-CSDN博客
参考官方博客:网易AirtestProject 的个人主页 - 动态 - 掘金
参考官方文档:欢迎使用 - Airtest Project Docs
目录
一:录制视频
airtest1.1.6支持 在 --recording
参数后面加上一个文件名来命名录屏文件 ,例如 --recording test.mp4
,如果有不止一台手机在运行,会把文件命名为 手机名_test.mp4
。
#开始录制/结束录制
start_recording() 和 stop_recording()
【回顾】在使用纯py文件编写脚本的时候,如使用了android手机,初始化连接
if not cli_setup():
auto_setup(__file__, logdir="./log", devices=["Android://127.0.0.1:5037/FIFIMFFEPVAIWCU8"])
devices:adb server所在主机的ip:adb port / 序列号,其中FIFIMFFEPVAIWCU8是序列号,通过这种方式可以查出
API:airtest.core.android.recorder module — airtest 文档
录屏的这两个方法 属于 Recorder(adb)
类,需要实例化这个类,才能通过实例去调用里面的方法
adb = ADB(serialno="FIFIMFFEPVAIWCU8")
recorder = Recorder(adb)
# 开始录屏
recorder.start_recording(max_time=10)
sleep(3.0)
# 结束录屏
recorder.stop_recording(output="dy.mp4")
在录制的时候,涉及密码输入,会出现黑屏,在安全设置中,把安全键盘之类的设置关掉 ,或者是 关掉其它一些防止恶意截屏录屏的设置。
二:报告
__author__ = "漫步云端"
__title__ = "打开我的页面"
__desc__ = """
前提:无;
步骤1:打开app;
步骤2:点击我的;
步骤3:断言;
"""
可以使用命令行:airtest info 脚本路径
, 可以获得airtest解析出来的脚本信息,类似这样的返回值
{"name": "untitled.air", "path": "untitled.air", "author": "user", "title": "脚本标题", "desc": "用例描述"}
三:截图
(1)自定义截图压缩精度
① 使用命令行启动,airtest run ... --compress quality
② 在脚本中自定义,优先级高于命令行,取值范围是1-99的正整数,airtest默认取10
import airtest.core.api import *
ST.SNAPSHOT_QUALITY = xxx # [1, 99]
# 在报告的该touch步骤中,保存的截图的精度为全局精度xxx
touch(xx)
# snapshot保存的截图精度也是全局精度xxx
snapshot(filename='./ok.jpg',msg="完成截图")
③ 设置某张图片的压缩精度
snapshot(quality=my_quality)
(2)自定义报告截图的最大尺寸
# 设置截图尺寸不超过600*600,如果不设置,默认为原图尺寸
ST.IMAGE_MAXSIZE = 600
# 在报告的该touch步骤中,保存的截图尺寸不超过600*600
touch(xx)
# 截图质量为90,尺寸不超过1200*1200
snapshot(filename="ok1.png", msg="ok1", quality=90, max_size=1200)
# 不设置的情况下,默认采用ST中的全局变量的数值,即600*600
snapshot(msg="ok2")
(3)局部截图/区域截图
如(0,160)(1067,551)
# crop_image()方法在airtest.aircv中,需要引入
from airtest.aircv import *
screen = G.DEVICE.snapshot()
# 局部截图
screen = aircv.crop_image(screen,(0,160,1067,551))
# 保存局部截图到log文件夹中
try_log_screen(screen)
(4)用log()接口在报告中显示信息/报错
【回顾】airtest报错in recv raise socket.error("socket connection broken")
原因是连接参数少写了一个
【回顾】看下API:airtest.core.android.adb module,导包写from airtest.core.helper import *,避免忘记导包
args
, 可以是字符串或是 traceback
对象(异常),现在还支持传入非字符串
timestamp
, 参数可以自定义当前这条 log
的时间戳,默认为当前时间
desc
, 自定义一个 log 标题
ata = {"test": 123, "time": 123456}
# 第一条log,步骤名显示title,截取一张屏幕截图
log(data, timestamp=time.time(), desc="title", snapshot=True)
# 第二条log,标记为报错步骤并截取一张屏幕截图
try:
1/0
except Exception as e:
log(e, snapshot=True)
# 第三条log,显示传入的字符串
log("中文")
# 这样也行
import traceback
try:
xxxx
except:
log("出错啦", traceback. format_exc())
四:脚本全局设置
在airtest.core.settings
里,提供了部分全局默认属性,可以修改全局设置,如:
from airtest.core.api import *
# airtest.core.api中包含了一个名为ST的变量,即为全局设置
ST.THRESHOLD = 0.8
如touch,如果在里面有指定threshold,则使用指定的,如果没有,则默认使用全局属性。
常见的全局属性:
- RESIZE_METHOD = staticmethod(cocos_min_strategy)
分辨率适配规则
https://airtest.doc.io.netease.com/IDEdocs/airtest_framework/1_script_settings/
比如,参数都不用动,中间的内容是根据原属性,改为我要的缩放规则即可
- THRESHOLD = 0.7 # [0, 1]
图像识别的阈值
- THRESHOLD_STRICT = 0.7 # [0, 1]
只用于assert_exists(图片)
接口
- OPDELAY = 0.1
每一个步骤的操作之间都会有一小段时间间隔,默认是0.1秒
- FIND_TIMEOUT = 20
图像查找时间,使用了该接口:touch、double_click、swipe(如果是a图片滑到b图片,只有a图片使用了该接口)、wait(在没有使用timeout的情况下使用了该接口)、assert_exists
- FIND_TIMEOUT_TMP = 3
图像查找时间,使用了该接口:swipe(如果是a图片滑到b图片,只有b图片使用了该接口)、exists、assert_not_exists
- PROJECT_ROOT = os.environ.get("PROJECT_ROOT", "") # for
using
other script
可以通过设定一个默认项目根目录PROJECT_ROOT
,让使用using
接口时能够在当前根目录下寻找别的子脚本,无需填写完整路径,让脚本之间相互调用使用更加方便
from airtest.core.api import *
ST.PROJECT_ROOT = "/User/test/project"
# test1.air的实际路径为/User/test/project/test1.air
using("test1.air")
#调用其他的脚本
from test1 import test
五:Firebase打包脚本
限制:
- 安卓原生应用的poco无法使用,因为无法从一个app去启动另外一个app。但是游戏引擎的poco均可使用。
- 部分airtest接口,无法使用该方式执行,例如
clear_app
install_app
uninstall_app
- 由于启动脚本时,会出现kivy闪屏图片,所以脚本以start_app()开始
- 打包时,因为涉及到文件删除操作,所以不要使用目标包体的目录(有些用户习惯性直接在生成包体的目录打开命令行安装,会导致无法进行下一次打包)
原理:
步骤
1(环境配置):java(jdk,非jre)、配置jdk环境,输入jarsigner,没报错即可(如果出现不是内部命令,则将环境配到系统变量即可)
2(打包流程)
然后将该apk和被测应用安装在手机上,
然后用adb指令启动测试脚本 adb shell am instrument -w com.netease.open.airbase/android.support.test.runner.AndroidJUnitRunner
六:进一步熟悉
(1)滑动
swipe_along目前只有在使用了默认的 minitouch
模式(Android10使用 maxtouch
)时才能使用
自定义点击或滑动操作的方案:https://airtest.doc.io.netease.com/IDEdocs/faq/3_api_faq/
(2)引用其他脚本
如果需要引用的子脚本路径统一都放在某个目录下,可以通过设定一个默认项目根目录 PROJECT_ROOT
,让使用 using
接口时能够在当前根目录下寻找别的子脚本,无需填写完整路径
如jb1.air路径是/User/test/project/jb1.air
其他脚本引用它则:
ST.PROJECT_ROOT = "/User/test/project"
using("jb1.air")
记住别漏了导入方法语句
from jb1 import xx方法
(3)输入无法使用解决方法
#如果遇到一些设备无法使用text(),可以这样
# 方法一
dev = init_device("Android")
dev.shell(shell("input text '123456'"))
# 方法二
dev = connect_device("Android://127.0.0.1:5037/P7CDU18C27000473")
dev.shell(shell("input text '123456'"))
# 方法三
init_device("Android", ime_method="ADBIME")
text("123456")
(4)输入和删除文字
#删除输入框内容
for i in range(10):
keyevent("67")
#poco写法:将输入框内容设置为空字符串
poco("xxx").set_text("")
# 设置文字
# airtest写法:
text("哈哈")
#poco写法:注意XXX是可输入控件
poco("XXX").set_text("哈哈")
(5)输入完毕后的回车与搜索键
text接口有默认参数enter=True,即输入完成后回车,部分输入框是search=True
注意:输入法的回车和换行不同于keyevent事件
(6)输入随机数
#输入随机数
import random
r = random.randint(1,100)
text(str(r))
(7)poco获取节点的text属性
#poco获取节点的text属性
a = poco(text="cs")
a.get_text()
a.get_name()
(8)自定义log级别
import logging
logger = logging.getLogger("airtest")
logger.setLevel(logging.ERROR)
(9)模拟鼠标右键
# 获取当前连接的窗口
dev = device()
# 拿到鼠标,并模拟鼠标的右键点击操作
dev.mouse.right_click(coords=(1920,100))
七:poco的元素定位
(1)借助IDE的poco辅助窗生成元素定位脚本
点检视器按钮(前两个都行),点元素,就能看到该元素所在的位置,点那个定位就能生成脚本(区别是第一个按钮锁住页面)
点录制按钮,点元素,然后就生成了脚本,去掉.click()即可
(2)利用基本选择器进行元素定位
(3)利用相对选择器进行元素定位
(4)利用空间顺序选择器进行元素定位
八:坐标介绍
(1)Airtest的坐标系
# Airtest的坐标系
# (1)touch-使用的是(x, y)绝对坐标
# (2)swipe-滑动起点和终点使用的是(x, y)绝对坐标
(2)poco的坐标系
poco点击默认是点在 anchorPoint [ˈæŋkə(r) pɔɪnt]上的,每个UI都会有一个 anchorPoint ,也就是检视器(Inspector)中UI包围盒的那个红点,大部分情况下 anchorPoint 都在UI包围盒的正中央
# (1)使用局部坐标系的click接口
# 引入局部坐标系来表示相对于某UI的坐标。
# 局部坐标系以UI包围盒左上角为原点,向右为x轴,向下为y轴,包围盒宽和高均为单位一。(如上图)
# 局部坐标系可以更灵活地定位UI内或外的位置,例如(0.5, 0.5)就代表UI的正中央,也就相当于我们上文中默认的anchorPoint;超过1或小于0的坐标值则表示UI的外面。
# 点击 anchorPoint 以外的其他指定位置时,可以传一个参数到 click 方法中,这个参数是一个用list或tuple表示的2维向量,
# 其 [x, y] 值分别表示相对于包围盒左上角的偏移量,左上角为 [0, 0] ,右下角为 [1, 1]
poco(text="口红").click([0,0])
# 改变以anchorPoint为起点,也可以使用focus方法
poco(text="口红").focus([0,0]).click()
# (2)使用归一化坐标系的swipe接口
# 将屏幕宽和高按照单位一来算,这样UI在poco中的宽和高其实就是相对于屏幕的百分比大小
# 好处:不同分辨率设备之间,同一个UI的归一化坐标系下的位置和尺寸是一样的,有助于编写跨设备测试用例
# 屏幕正中央一定是(0.5, 0.5)
# 也是以 anchorPoint 为起点,改变起点用focus 方法
假如在游戏中(如中心点(0.5,0.5)),那我想往右上走(如走到(0.9,0.1)),那我的偏移量为(0.4,-0.4),距离为sqrt(0.4*0.4)
cs = poco("xx")
cs.swipe('up')
# 向上向右滑动,duration是滑动时长
cs.swipe([0.4, -0.4], duration=0.5)
九:Airtest图像识别原理相关
默认情况下,Airtest会尝试用 SURFMatching
、TemplateMatching
和 BRISKMatching
这三种算法来进行图像识别
其中 TemplateMatching
属于 模板匹配算法,而 SURFMatching
和 BRISKMatching
则属于 特征点匹配方法。简单点说,模板匹配算法依赖 特征向量 来进行图像匹配,而特征点匹配算法则是依赖于 图像的特征点 。
# 程序如何根据算法结果判定是否找到匹配的截图?
# 阙值 和 可信度 ,他们的取值范围都是[0,1]。在每一条图像识别的脚本中,都会有1个用于结果筛选的阙值,默认值为0.7
# 执行截图脚本时
# 如果可信度>阙值,程序判定找到匹配结果
# 如果可信度<阙值,程序判定未找到匹配结果,循环用三种算法继续查找直到超时
十:截图技巧
(1)截取图标时尽量不要截入过多的背景内容
理论上图1的识别度比图2高,不过我看了一下精度,图2的更高
(2)启动应用
start_app()
支持Android和iOS设备,相对用截图脚本来启动应用
start_app("包名")
(3)用image editor查看截图识别结果的可信度
双击截图,进入图片编辑器,点击左上角的 snapshot+recognition
按钮
(4)用target_pos点击截图的不同位置
默认情况下,我们的截图脚本都是点击截图的中心位置,即 target_pos=5
对于一张截图来说,总共有9个 target_pos ,当我们把截图的 target_pos 设置成不同的值时,脚本会点击在截图不同的位置上
方法1:双击截图,进入图片编辑器,可以修改该值
方法2:可以直接写成代码的形式
touch(Template(r"1.png", target_pos=6, record_pos=(-0.434, -0.773), resolution=(900, 1600)))
(5)用坐标进行点击/滑动
如app的介绍页,由于图片经常变化,维护麻烦,可以使用坐标
(6)用keyevent("BACK")替代返回的截图脚本
Android设备可以使用这个
(7)画面切换
画面切换的时候,可以多使用wait或者sleep,再进行点击操作
(8)调整阙值
调的太低,容易把错误的结果通过
调的太高,容易把正确的结果不通过
方法1:双击截图,进入图片编辑器,可以修改该值
:方法2:
touch(Template(r"1.png", threshold=0.8, record_pos=(-0.021, 0.121), resolution=(900.0, 1600.0)))
方法3:全局的 threshold
from airtest.core.setting import Settings as ST
ST.THRESHOLD = 0.7 # 其他语句的默认阈值
注意:只适用于除断言语句之外的截图语句
断言只能通过下述方式进行设置:
from airtest.core.setting import Settings as ST
ST.THRESHOLD_STRICT = 0.7
(9)自定义语句(例如截图列表)
(10)通过poco的选择节点
比如删除(多选框)
(11)脚本测试遇到的情况
①写好的截图脚本在更换一台不同分辨率的手机/更换一个环境之后,就经常遇到执行失败的报错:
airtest.core.error.TargetNotFoundError: 'Picture Template(E:\\untitled.air\\1.png) not found in screen'
原因:图片识别有误差,在不同分辨率,或画面发生了一定变化
解决方法:修改截图
②运行后查看报告,发现识别出来的位置是一个错误的位置,但是airtest当做是正确的
解决方法:调整截图/阀值
③运行后查看报告,报告里能看到识别到了正确的位置,也点击成功了,但是实际上没有成功点到。
原因:如果有连续点击操作,屏幕内容可能会不断变化,有时候会导致脚本明明运行到了点击操作却发现没有生效的情况。这是因为屏幕内容切换速度过快,界面还未稳定的同时airtest就进行了元素识别和操作,导致没有成功点击到对应元素。
解决方法:给个等待时间
(12)利用灰度图识别
如有三个图片是一样的,前两个背景是红色,第三个是黄色
勾选了rgb,或者在代码加入rgb=True,则进行强制使用色彩图片识别,airtest会将红色的认为是相同的