演练:创建图像自动化测试项目
概述
CukeTest中的图像自动化的功能可以通过类似人类视觉的方式操作应用,具体来说,可以将控件的图片截屏创建为图案(Pattern)对象,在屏幕中查找到匹配这个图案的区域,然后进行自动化操作,它可以针对对象识别技术无法识别的区域进行定位,完成的自动化操作。
对于图像自动化的概念,其实虚拟控件功能中就有提及,虚拟控件能在有些场景下发挥作用,但也有局限性:
- 不能用于目标的位置无法确定时。因为虚拟控件本质上是记录区域的位置和尺寸,因此没有定位动态目标的能力。
- 虚拟控件无法独立存在,它要依赖某个父控件提供区域范围。它要作为其它对象的子对象来创建,也就是说虚拟控件无法作为独立的识别方案。
图像自动化的图案对象与虚拟控件的区别:
虚拟控件对象 | 图案对象 |
---|---|
坐标区域匹配 | 图像内容匹配 |
无法应对动态目标 | 实时的匹配目标位置 |
需要作为其它控件的子控件 | 可独立存在,也可作为其它控件的子控件 |
因此本次演练,我们使用在虚拟控件演示中使用过的Qt应用appchooser再次进行图像自动化,借此来切身的感受图像自动化与基于对象识别的其它桌面自动化的区别。
目标
本次演练的目标是掌握图像自动化,事实上这非常的简单,如果有过使用CukeTest进行桌面自动化的经验,甚至只要知道在哪里添加图案对象就可以了:
接着只要选择截图区域,这个区域的内容就会截图下来作为图案(Pattern)对象添加到模型树中,接下来就可以像对待普通控件一样,对其进行属性修改、方法调试等操作。
开始演练
创建项目
点击菜单或欢迎界面的“新建项目”进入到项目配置界面。需要配置的内容有三项:项目名称、项目路径和项目模版,最重要的应该是项目模版的选择,这里因为需要在模型文件中管理图案对象,因此选择包含模型文件的Windows模版。
Linux平台则选择桌面自动化模版,比如Qt。
项目名称 | 项目模版 | 项目路径 |
---|---|---|
GraphicAutomation | Windows(Qt) | 任意路径 |
编辑剧本并生成脚本模版
因为是测试项目,首先需要的就是确认测试步骤,这些步骤的描述写到feature
文件也就是剧本文件中。因为我们的测试目标是使用图像自动化来完成应用操作,而被测应用appchooser的逻辑也比较简单,点击图案后,图案会放大并移动到中央,所以测试步骤也比较简单:
- 启动应用
- 循环点击四个图案2次并统计识别时间
- 关闭应用
打开项目目录中的feature1.feature
文件,写入以上步骤,得到:
打开项目中的definition1.js
脚本文件,再依次点击剧本文件中的灰色箭头生成脚本模版,如下:
添加图案对象
在文件视图中找到features/step_definitions
路径下的模型文件model1.tmodel
,单击文件会在模型管理器中打开。接着打开被测应用——Qt示例应用appchooser
,可以在CuketeTest主界面的菜单栏选择【工具】->【启动桌面样例】中找到,也可以在模型管理器窗口的菜单栏选择【操作】->【样例应用】中找到。做好这些工作后,现在你的界面看起来应该是这样:
点击工具栏的“添加图案对象”按钮进入截图状态,分别截图选中被测应用中的四个角的图案并添加到模型树中。
注意:
应该尽量的使截图区域不超出应用,否则截图中的多余区域会影响匹配过程。
将四个角的图案都截图好添加到模型树后如下:
在属性框中修改对象名字,以便于理解:
调试方法
识别到对象以后就可以在对象的“控件操作”栏进行方法调试,比如在“相机”对象的控件操作栏中选中click()
方法,然后点击标签页下方的扳手按钮“缺省调用”调试选中的click()
方法:
对于“缺省调用”功能,是使用默认参数调用选中的方法,各个方法的默认参数是什么可以查阅各自的API文档。而其隔壁的绿色扳手,会打开参数面板,填入参数后进行调用。
编写脚本
属性面板中的操作方法除了可以调试,也可以直接生成可运行的脚本,点击“复制方法代码到剪贴板”按钮,接着复制到脚本编辑器中即可:
接下来开始正式针对剧本文件中的测试步骤编写脚本。
步骤一:启动应用
首先是启动应用,在界面左侧的工具箱选项卡中找到【常用】-【launchProcess
】工具,拖拽到脚本中,再输入应用appchooser的可执行文件路径(应用在CukeTest安装路径的 bin 目录下,如"C:/Program Files/LeanPro/CukeTest/bin/appchooser.exe
")。得到脚本如下:
Given("启动应用", async function () {
Util.launchProcess("C:/Program Files/LeanPro/CukeTest/bin/appchooser.exe");
});
这就结束了?当然没有,由于操作应该在应用完全启动后再执行,因此我们需要判断应用成功启动后才算完成这一步骤,这里使用到图案对象的wait(seconds)
方法,能够等待应用出现,超时报错,具体介绍点击查看。
所以我们通过判断相机
这一图案是否出现来确认应用是否打开,“启动应用”这一步骤脚本可以进一步优化为:
Given("启动应用", async function () {
Util.launchProcess("C:\\Program Files\\LeanPro\\CukeTest\\bin\\appchooser.exe");
await model.getPattern("相机").wait(5);
});
等待5秒即可,对于其它大型应用可以适当延长。
步骤二:循环点击四个图案{number}次并统计识别时间
通过观察从剧本文件生成的脚本模版,发现步骤二的描述与生成的剧本有区别:
剧本中的步骤描述:
循环点击四个图案2次并统计识别时间
脚本中的模版:
When("循环点击四个图案{int}次并统计识别时间", async function (arg1) {
return 'pending';
});
仔细观察后可以发现,步骤描述中的数字变为了{int}
,而这正是CukeTest对步骤描述的参数化处理。简单来说,就是步骤中的数字会被作为传入到后面的脚本中的参数被解析,也就是脚本中arg1
参数,接着你可以在脚本中调用这些参数,以完成灵活的步骤配置。
并且这个
arg1
参数你可以修改为任何你喜欢的变量名,比如这里参数代表的是循环次数,所以可以将其命名为count
,下面的脚本中也都是当作count
来编写的。
When("循环点击四个图案{int}次并统计识别时间", async function (count) {
const ptns = ["相机", "眼镜", "字典", "图标"];
for (let i = 0; i < count; i++) {
for (let ptn of ptns) {
let beforeTime = new Date().getTime();
await model.getPattern(ptn).click();
let afterTime = new Date().getTime();
let duration = afterTime - beforeTime;
console.log(`寻找图案${ptn}耗费时间${duration}ms.`);
}
}
});
步骤三:关闭应用
完成了所有操作后,应该把被测应用关闭,使得这一测试场景形成闭环,可以独立的运行不受其它场景干扰。那么关闭应用最快速的方法还是获取应用的进程号pid,而在步骤一中调用launchProcess()
方法中,方法的返回值就是进程信息,将其传入到stopProcess()
方法中即可关闭由launchProcess()
方法启动的应用。stopProcess()
方法同样在界面左侧的工具箱选项卡的【常用】模块可以找到。为了让步骤三能够使用到步骤一的变量,我们需要对步骤一的脚本也进行修改:
let pid;
Given("启动应用", async function () {
pid = Util.launchProcess("C:\\Program Files\\LeanPro\\CukeTest\\bin\\appchooser.exe");
await model.getPattern("相机").wait(5);
});
Then("关闭应用", async function () {
Util.stopProcess(pid);
});
其实就是把变量
pid
提升到函数外,使其作用域提升到整个文件。
运行结果
点击工具栏中的“运行项目”按钮,或使用快捷键CTRL+R
开始运行,运行结束得到运行报告和控制台输出如下: