构造Egret节点树的 Canvas 穿透自动化测试方案
一、背景
目前项目组的回归测试大多数还是依赖分配人力手动回归,但随着版本迭代,需要回归的日渐增多。自动化测试可以在回归阶段减少大量的人力投入,稳定的自动化测试可以保证用例执行的正确性,缩短回归阶段的用时,提高效率。但传统的h5自动化测试框架基于html 标签节点进行操作,并不适用于基于Canvas渲染的游戏项目。本文拟提出一种对Canvas渲染的项目有效的自动化测试方案。
二、项目目标
- 产出针对Egret游戏项目有效的自动化测试驱动
- 驱动可实时获取当前游戏状态的egretObject对象,构造类H5标签的EgretObject节点树
- 驱动提供EgretObject搜索方法,如getElementByName等
- 驱动提供操作EgretObject的基本方法,如:Click、DoubleClick、Move等方法
- 驱动提供获取EgretObject基本属性的方法,如:text、source、name、width、height等属性
最终测试人员可以通过引用对应的驱动快速编写代码,组建自动化测试用例,自动化测试可靠稳定进行。
三、Egret Object 节点
在介绍项目结构之前,有必要先介绍一下Egret Object节点大概长什么样子。首先看看这款谷歌插件egret-inspector如下图所示。
安装启动插件,我们可以在浏览器中看到Egret项目当前渲染的节点信息,选中某个节点,可以在插件里面看到这个节点的相关参数,包括节点的x,y (位置)、width、height(长宽)、text(文本信息)、source(图片资源)等等。可以看出来Egret节点的组织结构和属性与H5标签类似。
项目对Selenium进行了封装,并提供系列方法给开发者调用,下文称为本项目为EgretDriver。通过往Egret项目中注入Egret原生方法可以得到当前项目渲染的Egret Object节点,在EgretDriver中,我们定时获得最新的EgretObject节点,转化并维护一颗EgretObjectTreeNodes,同时提供了getElement() TapElement() getProperty()等方法用于搜索、操作EgretObjectTreeNodes 上的子节点。用户可以调用EgretDriver提供的方法简单的编写自动化测试用例,用于回归。
五、项目演示
这是一个简单的demo
from egretDriver import egretDriver
import time
egretDriver = egretDriver.EgretDriver()
driver = egretDriver.driver
driver.get('https://*')
driver.add_cookie({
"domain": "",
"name": '',
"value": '',
"path": '/',
"expires": None
})
driver.get('https://*')
time.sleep(5)
# 启动节点树初始化
egretDriver.initTreeNode()
# 等待此元素加载
egretDriver.wait('name', '"QUICK_START"')
# 点击开局按钮
elements = egretDriver.getEgretElements('name', '"QUICK_START"')
QUICK_BTN = elements[0]
print('点击START 按钮')
egretDriver.tap(QUICK_BTN)
egretDriver.wait('name', '"CommonPropIconList"')
print('开局道具 图片资源')
# 道具列表的资源
CommonPropIconList = egretDriver.getEgretElements('name', '"CommonPropIconList"')
for prop in CommonPropIconList[0]['children']:
prop_group = prop['children'][0]['children'][0]['children']
source1 = prop_group[0]['source']
egretDriver.tap(prop_group[0])
print(source1)
print('开局道具 底板资源 & 数量')
# 道具数量
CommonPropLabelList = egretDriver.getEgretElements('name', '"CommonPropLabelList"')
for prop in CommonPropLabelList[0]['children']:
prop_group = prop['children'][0]['children']
source1 = prop_group[0]['source']
source2 = prop_group[1]['source']
prop_num = prop_group[2]['text']
print(source1, source2, prop_num)
在demo中我们执行了以下操作
- 引入了EgretDriver,访问了项目地址,初始化了节点树
- 接着找到了名为”QUICK_START”的元素并点击(点击Play按钮)
- 等待”CommonPropIconList”元素出现(开局弹窗弹出)
- 页面渲染”CommonPropIconList”对象后,遍历他的子节点,输出对应source属性(其引用的图片名称 ),然后点击(选中道具)
- 用类似的方法找到并输出了”CommonPropLabelList”子节点的text属性(道具数量)
EgretDriver提供的 方法是类似于selenium的,用简单的方法可以定位元素,获取元素属性。
六、项目细节
- EgretObject对象获取、EgretObjectTreeNodes构建
在Egret项目中通过执行 egret.MainContext.instance.stage 可以获得EgretObject节点树的根节点,这和Egret插件的节点树是一致的。
selenium driver的 execute_script() 可以执行js方法在EgretDriver中获得节点树,但是由于egret.MainContext.instance.stage 获得的节点树存在父子节点循环引用的问题,需要额外封装js function获得非循环引用的EgretObject节点树。 - 元素相对定位转化为绝对定位
元素操作还是基于selenium再次封装的,所以需要获得当前页面元素所处于的绝对定位,但是上面获得节点中的x,y属性存在两个问题:Q1. 在实际中发现,通过egret.MainContext.instance.stage获得的元素位置信息(x, y)是相对于项目定义的项目长宽(即使在不同分辨率设备下获得到的位置始终是(x,y))。如果项目定义的长宽是(750,1334),元素的(x, y)指的是当当前分辨率为750*1334时候,元素位于(x, y),但是很多不同设备下,分辨率不为750*1334。所以在当前设备操作元素时实际操作的(x’, y’)需要根据当前分辨率等比例转化。
Q2.该(x, y)是相对于父节点的相对位置, 如某child节点定位为(x,y),其parents节点的绝对定位为(x1,y1),所以child的绝对定位应为(x1+x, y1+y)。EgretDriver在构造节点树的时候就已经完成了当前分辨率等比例的转换以及节点绝对定位的转换。在调用EgretDriver.TapElement()方法的时候,底层实现是点击了元素绝对定位的坐标,但已经完成封装,并不需要开发者关注。七、拓展
EgretDriver目前已经实现了较为常用的核心方法,但是目前要实现自动化依旧需要手动编写代码。但依旧有思路可以方便自动化脚本的生成,比如说监听用户的点击行为,映射操作坐标至对应的EgretObj的操作,生成对应的自动化脚本,相当于录制一次用户的行为就可以生成本次操作所对应的自动化脚本,快速实现操作回放。
发表评论