youqu/docs/智能化功能测试.md

18 KiB
Raw Blame History

智能化功能测试

# Attribution Chengdu Test Team
# Date        2021/08/20

此方案仍在演进中

仓库地址:https://gitlabcd.uniontech.com/autotest/cd-desktop-aitest

一、方案概述

基于深度学习智能识别应用的元素控件,用于在自动化测试操作过程中的元素定位以及判断结果时的断言处理;自动化测试过程中,测试机上的画面通过采集盒传输到服务器上,服务器对视频画面进行智能识别后,服务器智能判断用例是否执行成功,然后对测试机下发下一步操作指令,测试机接受并执行下一步操作。

服务器与测试机之间的链接:

  • 服务器通过 USB 串口设备USB-HID 协议)模拟鼠标键盘对测试机进行操作。
  • 通过视频采集设备捕获测试机的实时画面传输给服务器。

服务器对采集的画面进行智能识别,识别其中的元素控件,并返回元素控件在屏幕中的坐标,服务器通过智能化分析,如果测试结果与预期一致将下一步操作指令通过串口模拟键鼠信号发送给测试机;如果测试结果与预期不一致将会进入中断处理及异常结果输出,继续执行后续场景,直至所有用例测试完成。

二、深度学习环境搭建

模型训练主要对 GPU 有要求,训练模型的机器显存不低于 6G其他配置无特殊要求。

推荐性价比较高配置

操作系统: UnionTech OS Desktop 20 Professional Linux version 4.19.0-desktop-amd64 (deepin@deepin-PC) (Uos 8.3.0.3-3+rebuild) 
处理器: Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz (八核 / 十六逻辑处理器)
主板: B460M-HDV(RD)
内存: 8GB(TF32D4U2S1MEH-8 DDR4 2933MHz (0.3ns))/8GB(TF32D4U2S1MEH-8 DDR4 2933MHz (0.3ns))
显示适配器: TU116 [GeForce GTX 1660]

1、虚拟环境安装

cd ~
wget -c https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh

一路回车

第一次提示输入 yes/no :输入 yes

继续一路回车

第二次提示:输入 no

cd ~/miniconda3/bin
sudo chmod 777 activate

激活conda环境

. ./activate

添加公司内网源

conda config --add channels bioconda
conda config --add channels conda-forge

如果是外网添加外网源

conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/

如果要删除源

conda config --remove-key channels

2、安装依赖

1创建虚拟环境

conda remove --name mmlab --all # 移除所有虚拟环境
conda create -n mmlab python=3.7
conda activate mmlab

2安装 Pytorch

在mmlab虚拟环境中执行

pip install torch==1.7.0+cu101 torchvision==0.8.1+cu101 torchaudio==0.7.0 -f https://download.pytorch.org/whl/torch_stable.html -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

3安装 MMCV

在mmlab虚拟环境中执行

pip install mmcv-full==1.3.3 -f https://download.openmmlab.com/mmcv/dist/cu101/torch1.7.0/index.html -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

4安装显卡驱动

根据你的显卡下载对应驱动,比如我的显卡为 GTX1660,驱动版本为 430驱动下载地址https://www.nvidia.cn/Download/Find.aspx?lang=cn

CTRL+ALT+F2 进入tty

禁用 nouveau 驱动

sudo vim /etc/modprobe.d/blacklist-nouveau.conf

填入:

blacklist nouveau 
options nouveau modeset=0

刷新配置文件

sudo update-initramfs -u 

reboot 重启后再进入 tty

关闭图像界面,输入命令关闭图像界面

sudo service lightdm stop

安装驱动

sudo chmod a+x NVIDIA-Linux-x86_64-430.run
sudo ./NVIDIA-Linux-x86_64-430.run

reboot重启nvidia-smi查看安装状态。注意看下cuda版本10.1driver版。

三、数据标注

1、数据标注

标注之前需要先转换图片大小,并且以数字命名,每组命名递增

1转换大小并重命名

rename_pic.py

import os
import sys
import cv2
import time
import getpass
username = getpass.getuser()

source_path = f"/home/{username}/Desktop/right_menu" # 图片路径

source_dest = os.path.join('/'.join(source_path.split("/")[:-1]), 'tmp')
if not os.path.exists(source_dest):
    os.mkdir(source_dest)

start_name = sys.argv[1]

file_name_list = list()
for file in os.listdir(source_path):
    if file.endswith('.png'):
        file_name_list.append(file)
start_name = int(start_name)
for file in file_name_list:
    os.rename(os.path.join(source_path,file), os.path.join(source_path, f"{str(start_name)}.png"))
    start_name += 1

time.sleep(1)

for file in os.listdir(source_path):
    image = os.path.join(source_path, str(file))
    src = cv2.imread(image)
    result = cv2.resize(src, (960, 540))
    resizeImage = os.path.join(source_dest, str(file))
    print(resizeImage)
    cv2.imwrite(str(resizeImage), result)
cv2.waitKey(0)
cv2.destroyAllWindows()

time.sleep(1)

os.system(f'rm -rf {source_path}/*')
os.system(f'mv {source_dest}/* {source_path}')
os.system(f'rm -rf {source_dest}')

print("下一个序号:", start_name)

根据终端输出的下一个序号的提示,执行 Python 文件的时候传参。

python rename_pic.py 249

2工具标注

使用工具 labelImg 标注

sudo pip3 install PyQt5==5.13
sudo pip3 install labelImg

终端直接输入 labelImg回车

标注模式选择:PascalVOC

2、智能标注

打开屏幕录制软件,录制手动操作一次测试用例,然后将录制的视频进行分帧,然后对比前两帧图标相似度,剔除相似度过高的图片,在保证素材多样性的前提下,剔除重复多余的图片生成待标注的素材集,然后取出控件模板数据集,通过 OpenCV 模板匹配获取控件在待标注的素材图片中所在的左上、左下、右上、右下四处坐标,从而根据模板数据集生成标注数据。参考目录 AnnotationMaterial

1模板数据集准备

1、在界面截取需要标注的元素控件放在目录下 AnnotationMaterial/template/img

2、维护控件名与元素控件的键对一个控件名可对应多个元素控件

menu:
    - menu.jpg
    - menu1.jpg
    - menu2.jpg
    - menu3.jpg

2素材集准备

录制视频或或屏幕截图放置目录 AnnotationMaterial/source

3开始标注

python3 AnnotationMaterial/main.py

生成的标注数据存放在 AnnotationMaterial/result

四、MMDetection

1、 MMDetection 代码

MMDetection 是一个有名的深度学习目标检测开源项目,也是 openMMlab 的招牌项目,为什么选择它,小孩儿没娘说来话长,感兴趣可以自行深入了解;

你可以直接在 GitHub 上克隆代码,也可以直接使用咱们仓库下 Train 目录中代码Train 中的代码也是从 GitHub 上拉取的,不过我们根据项目需要做了一些二次开发,推荐直接使用它。

如果你想从 GitHub 上拉:

git clone https://github.com/open-mmlab/mmdetection.git
# 不能直接拉取主分支建议使用2.12版本不同的版本对应的mmcv版本是不同的

2、拉取 voc2coco 代码

git clone https://github.com/Tony607/voc2coco.git

3、转换 coco 数据集

将所有的图片和xml文件放入train2017从中挑选几组放入val2017测试集

cd mmdetection/data/coco
python voc2coco.py train2017 annotations/instances_train2017.json
python voc2coco.py val2017 annotations/instances_val2017.json

生成json文件

4、修改配置

1读取模型名称

import json

module_name = []
with open('./instances_train2017.json', "r+") as f:
    json_file = f.read()
json_dict = json.loads(json_file)
module_list = json_dict.get('categories')
for module_info in module_list:
    name = module_info.get('name')
    module_name.append(name)
print(module_name)
print("module_num:", len(module_name))
# 注意对比instances_train2017.json里面模型名称的顺序与CLASSES和coco_classes里面的顺序保持一致。

2修改 faster_rcnn_r101_2x_coco.py

mmdetection/xianjin/faster_rcnn_r101_2x_coco.py

修改46行num_clasess的值新增1个就 +1

3修改 coco.py

mmdetection/mmdet/datasets/coco.py

CLASSES = (),在里面添加模型名称;

4修改 class_names.py

mmdetection/mmdet/core/evaluation/class_names.py

coco_classes 里面添加模型名称;

5、缓存清理

删除 mmdetection/build 目录

python setup.py install

6、训练模型

1指定自己配置的训练模型

python tools/train.py xianjin/faster_rcnn_r101_fpn_2x_coco.py --gpus 1

2查看训练结果的测试集结果

python tools/train.py xianjin/faster_rcnn_r101_fpn_2x_coco.py xianjin/epoch_24.pth --show

3查看训练结果的准确度

python tools/analysis_tools/analyze_logs.py plot_curve xianjin/20210530_011907.log.json --keys acc

7、快捷操作

python3 run.py

将以上 4 - 7 步操作整合成 run.py一键完成。

五、硬件环境

1、设备清单

2、硬件环境搭建

  • 采集盒HDMI 端连接测试机, USB 端连接到服务器上;
  • USB 串口线,白色端连接服务器,黑色端连接测试机;
  • 如果需要可以接USB延长线
  • 测试机上可以不接显示器;

3、推荐配置

执行用例的服务端对配置没有特殊要求,如果条件允许配置越高,识别速度用例执行速度越快。

处理器: Intel(R) Core(TM) i3-10100 CPU @ 3.60GHz (四核 / 八逻辑处理器)
主板: B460-N2(J)
内存: 8GB(TF32D4U2S1MEH-8 DDR4 3200MHz (0.3ns))
显示适配器: UHD Graphics 630
存储设备: FORESEE P900F256GBH (256 GB)/ST1000DM003-1SB102 (1.00 TB)

测试机上不执行任何脚本,具体配置根据测试需要决定。

六、USB_MK串口驱动方法

位于control_method目录下的usb_mk.py文件

1列出可通信的端口

python3 -m serial.tools.list_ports -v

2修改串口的权限

sudo chmod 777 /dev/ttyACM0

3实例化USB_MK

import UsbMk
usb_mk = UsbMk("/dev/ttyACM0", 9600)   # 设备默认9600为波特率控制传输速率

4USB串口设备默认波特率为9600经测试波特率9600准确性最好

1、键盘操作

1按下键盘按键

usb_mk.press_key("enter")   # 按下键盘enter键

2按下键盘按键并且不放

usb_mk.press_key_down("enter")   # 按下键盘enter键不放

3组合按键

usb_mk.hot_key("ctrl", "alt", "T")   # 按下组合按键ctrl+alt+T调起终端

4组合按键不放

usb_mk.hot_key_down("ctrl", "alt", "T")   # 按下组合按键ctrl+alt+T调起终端不放

5释放所有键盘按键

usb_mk.key_up()   # 释放所有键盘按键

6键盘输入字符串汉字会自动转成拼音输入

usb_mk.hot_key("ctrl", "alt", "T")   # 按下组合按键ctrl+alt+T调起终端
usb_mk.input_text("reboot")   # 输入字符串reboot
usb_mk.press_key("enter")   # 按下键盘enter键

2、鼠标操作

1按下鼠标左键

usb_mk.click()   # 按下鼠标左键

2按下鼠标左键不放

usb_mk.mouse_down()   # 按下鼠标左键不放

3释放鼠标所有按键

usb_mk.mouse_up()   # 释放鼠标所有按键

3按下鼠标右键

usb_mk.right_click()   # 释放鼠标所有按键

4鼠标左键双击

usb_mk.double_click()   # 释放鼠标所有按键

5恢复鼠标至初始位置默认左上角

usb_mk.move_to_init()   # 恢复鼠标至初始位置,默认左上角

6移动鼠标至相对坐标

usb_mk.move_rel(100, 200)   # 鼠标向左边移动100个像素向下移动200个像素

7以屏幕左上角为圆心坐标移动鼠标至屏幕绝对坐标

usb_mk.move_to(100, 200)   # 鼠标移动至屏幕坐标100, 200
# 注因Linux系统不支持鼠标绝对路径所以会鼠标会先移动到初始位置

8按下鼠标左键拖动到绝对坐标位置

usb_mk.drag_to(100, 200)   # 按下鼠标拖动至屏幕坐标100, 200
# 注因Linux系统不支持鼠标绝对路径所以会鼠标会先移动到初始位置

9按下鼠标左键拖动到相对坐标位置

usb_mk.drag_rel(100, 200)   # 鼠标向左边移动100个像素向下移动200个像素

七、方法调用入参规则

1、基类

class Base:

    def __init__(self):
        self._obj = image
        self._usb = usb_mk

    def find_element_by_ai(self, element):
        return self._obj.find_element(element)

2、入参说明

图像识别方法入口为 Base 类下的 find_element_by_ai 。仅接受一个参数 element类型为 string。

可识别的 string 格式:

1大图标 图标大于 40 像素):识别某个大图标,例:

Base().find_element_by_ai("window")

2大图标 / 小图标(图标小于 40 像素识别某个小图标window/search_btn

Base().find_element_by_ai("window/search_btn")

3大图标 / OCR识别某个大图标内的文字menu/属性

Base().find_element_by_ai("menu/属性")

4OCR全屏识别文字

Base().find_element_by_ai("搜索")

八、隐藏鼠标

通过采集盒传输过来的视频流,在识别过程中可能受到鼠标影响,因此用例执行过程中需要隐藏鼠标。

屏蔽鼠标光标显示

 /etc/lightdm/lightdm.conf

[Seat:*]下面添加参数

xserver-command=X -bs -core -nocursor

九、智能自动化的意义

1、改善 Acessibility 定位的稳定性问题

Acessibility 属性定位存在偶尔失效的情况

1开发在做新需求开发时可能涉及到对属性标签的修改或者层级的调整可能造成自动化用例无法定位到元素。

  • 比如1040阶段音乐重构的时候开发对部分属性和层级做了修改导致自动化用例定位方法80%需要修改。
  • 开发新功能的时候偶尔也会对属性做调整遇到5次。

2目前主要使用Dogtail识别应用Acessibility属性进行定位是获取应用当前界面的属性tree在应用跳转后Dogtail存在无法及时获取当前属性列表的情况。

  • 多媒体调用文管窗口的时候出现找不到文管里面元素的情况目前出现10+次。
  • 应用设置页面的属性偶尔存在找不到的情况遇到5次。

3Dogtail工具本身存在问题有时定位元素的时候很慢让人无法接受目前出现过很多次。

  • 执行用例的时候定位元素的时间比平常慢3倍出现4次。

2、解决了使用绝对图像识别定位的容错性差的问题

部分控件无法添加 Acessibility 属性从而使用图像识别定位出现的容错性差的问题。

1图像识别定位方法需要维护大量的目标图片资源在 UI 发生变化之后,会涉及到目标资源的替换,比较耗费人力。

2图像识别的定位方法对比精度比较搞如果UI 的变更会造成无法准确定位到,自动化脚本健壮性不足。

3、使用机器分离解决了自动化脚本对应用的影响真实还原用户的使用场景

机器分离的架构设计,保证了测试机的测试环境完全等同于用户,排除测试脚本的影响。

1目前的功能自动化是在测试机上直接运行自动化测试脚本加上用例执行过程中我们添加了一些进程监控、视频录制等功能自动化脚本本身会消耗一些系统资源无法还原真是的用户使用场景。

2性能测试需要排除其他程序的资源消耗影响性能自动化采用机器分离保证了性能数据的准确性。

以前的用例执行耗时没条在30秒左右现在用例耗时在10秒。

4、解决了UI 调整导致定位失败的不稳定性问题

1解决了因 UI 调整导致控件位置变化或色差变化后定位不准确的问题,只要控件文案和控件外边框无变化均可准确定位;

2目前也会采用基于UI的定位方案如果UI位置有调整会导致元素无法定位。

5、简化了用例结构提升编写友好度

1智能自动化识别元素的方法只有一个就是基于我们训练的模型识别视频流中的元素经过脚本封装之后在自动化用例中所有定位的操作都只需要调用这一个方法就行了编写自动化脚本的难度大大降低。

2也是由于调用方法简单在 UI 自动化测试框架中的分层结构将会减少,多继承的情况会减少,自动化代码的调用结构也会变得简单,而且功能测试同学编写自动化用例会更加容易上手。

以前写用例由于需要结合不同的模块调用不同的方法编写一条用例并完成调试的时间平均在20-30分钟现在写用例脚本能在5分钟左右完成。