前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >15.UI自动化测试框架搭建-借鉴AirTest框架Template定位元素

15.UI自动化测试框架搭建-借鉴AirTest框架Template定位元素

作者头像
zx钟
发布2022-04-27 09:46:48
5950
发布2022-04-27 09:46:48
举报
文章被收录于专栏:测试游记测试游记

在进行UI自动化测试的时候,有些元素难以匹配,需要采用图片比对的方式找到并操作。

阅读一下AirTest的代码来借鉴一下

安装

下载一个AirtestIDE。下载地址:https://airtest.netease.com/

找到代码入口

  1. 新建一个py脚本
  2. 连接上测试手机
  3. 点击touch并框选一个图片
  4. 使用Pycharm打开该文件

安装airtest

代码语言:javascript
复制
pip install airtest

查看代码

阅读入口代码

代码语言:javascript
复制
# -*- encoding=utf8 -*-
__author__ = "zhongxin"

from airtest.core.api import *
from airtest.cli.parser import cli_setup

if not cli_setup():
    auto_setup(__file__, logdir=True, devices=[
        "android://127.0.0.1:5037/xxxx?cap_method=MINICAP&&ori_method=MINICAPORI&&touch_method=MAXTOUCH", ])

# script content
print("start...")

touch(Template(r"tpl1648886223193.png", record_pos=(-0.343, -0.643), resolution=(1080, 2400)))

# generate html report
# from airtest.report.report import simple_report
# simple_report(__file__, logpath=True)

这个文件旁边还有一个tpl1648886223193.png图片文件

touch()完成了元素的点击操作

阅读touch方法

代码语言:javascript
复制
@logwrap
def touch(v, times=1, **kwargs):
    if isinstance(v, Template):
        pos = loop_find(v, timeout=ST.FIND_TIMEOUT)
    else:
        try_log_screen()
        pos = v
    for _ in range(times):
        G.DEVICE.touch(pos, **kwargs)
        time.sleep(0.05)
    delay_after_operation()
    return pos

传入的对象是Template所以把这段代码简化一下

代码语言:javascript
复制
pos = loop_find(v, timeout=20)
G.DEVICE.touch(pos, **kwargs)

使用了loop_find找到了pos然后touch了一下

根据编写Selenium代码的经验,大概可以猜测G.DEVICE是一个类似driver对象的操作对象

阅读它的代码也可以看出来,不过不看了

阅读loop_find方法

代码语言:javascript
复制
@logwrap
def loop_find(query, timeout=ST.FIND_TIMEOUT, threshold=None, interval=0.5, intervalfunc=None):
    G.LOGGING.info("Try finding: %s", query)
    start_time = time.time()
    while True:
        screen = G.DEVICE.snapshot(filename=None, quality=ST.SNAPSHOT_QUALITY)

        if screen is None:
            G.LOGGING.warning("Screen is None, may be locked")
        else:
            if threshold:
                query.threshold = threshold
            match_pos = query.match_in(screen)
            if match_pos:
                try_log_screen(screen)
                return match_pos

        if intervalfunc is not None:
            intervalfunc()

        # 超时则raise,未超时则进行下次循环:
        if (time.time() - start_time) > timeout:
            try_log_screen(screen)
            raise TargetNotFoundError('Picture %s not found in screen' % query)
        else:
            time.sleep(interval)

简化一下

代码语言:javascript
复制
screen = G.DEVICE.snapshot(filename=None, quality=ST.SNAPSHOT_QUALITY)
match_pos = query.match_in(screen)

这里进行了一次屏幕截图,然后调用了match_in方法

阅读Template.match_in方法

这个方法进入了Template类了,对外除了实例化应该就用了这个类中的这个方法

代码语言:javascript
复制
def match_in(self, screen):
    # screen 当前页面截图
    match_result = self._cv_match(screen)
    G.LOGGING.debug("match result: %s", match_result)
    if not match_result:
        return None
    focus_pos = TargetPos().getXY(match_result, self.target_pos)
    return focus_pos

简化

代码语言:javascript
复制
match_result = self._cv_match(screen)
focus_pos = TargetPos().getXY(match_result, self.target_pos)
阅读 _cv_match方法
代码语言:javascript
复制
@logwrap
def _cv_match(self, screen):
    ori_image = self._imread()
    image = self._resize_image(ori_image, screen, ST.RESIZE_METHOD)
    ret = None
    for method in ST.CVSTRATEGY:
        func = MATCHING_METHODS.get(method, None)
        if func is None:
            raise InvalidMatchingMethodError("Undefined method in CVSTRATEGY: '%s', try 'kaze'/'brisk'/'akaze'/'orb'/'surf'/'sift'/'brief' instead." % method)
        else:
            if method in ["mstpl", "gmstpl"]:
                ret = self._try_match(func, ori_image, screen, threshold=self.threshold, rgb=self.rgb, record_pos=self.record_pos,
                                        resolution=self.resolution, scale_max=self.scale_max, scale_step=self.scale_step)
            else:
                ret = self._try_match(func, image, screen, threshold=self.threshold, rgb=self.rgb)
        if ret:
            break
    return ret

简化一下

上半部分

代码语言:javascript
复制
ori_image = self._imread()
image = self._resize_image(ori_image, screen, ST.RESIZE_METHOD)

ori_image:读取目标图片

在截取tpl1648886223193.png图片文件的时候 IDE把要定位的图片+定位时的屏幕分辨率当做参数传入了Template类中

这时就可以根据(要定位的图片+要定位图片截图时候的屏幕分辨率)+ 当前屏幕的分辨率 + 算法(ST.RESIZE_METHOD) => 缩放后的当前屏幕图片image

下半部分

代码语言:javascript
复制
for method in ST.CVSTRATEGY:
    func = MATCHING_METHODS.get(method, None)
代码语言:javascript
复制
CVSTRATEGY = ["mstpl", "tpl", "surf", "brisk"]
MATCHING_METHODS = {
    "tpl": TemplateMatching,
    "mstpl": MultiScaleTemplateMatchingPre,
    "gmstpl": MultiScaleTemplateMatching,
    "kaze": KAZEMatching,
    "brisk": BRISKMatching,
    "akaze": AKAZEMatching,
    "orb": ORBMatching,
    "sift": SIFTMatching,
    "surf": SURFMatching,
    "brief": BRIEFMatching,
}
代码语言:javascript
复制
ret = self._try_match(func, image, screen, xxx)

遍历4种图片比对算法,得到ret

在math_in方法里面有一句

代码语言:javascript
复制
G.LOGGING.debug("match result: %s", match_result)

也就是这个结果会被打印出来。查看一下AirtestIDE的日志

代码语言:javascript
复制
[15:57:10][DEBUG]<airtest.core.api> match result: {'result': (170, 508), 'rectangle': ((69, 412.55999999999995), (69, 604.56), (272, 604.56), (272, 412.55999999999995)), 'confidence': 0.9397624135017395, 'time': 0.041297197341918945}
阅读getXY方法

该方法是获得目标的不同位置的坐标

从这里可以看出来result就是匹配到的要点击的图片的中间

rectangle则是要点击图片的四个角的坐标

小结

到此我们可以通过上述代码来实现获取目标位置坐标

接下来把他们拷贝出来整理整理就可以了

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-04-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 测试游记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 安装
  • 找到代码入口
  • 安装airtest
  • 查看代码
    • 阅读入口代码
      • 阅读touch方法
        • 阅读loop_find方法
          • 阅读Template.match_in方法
            • 阅读 _cv_match方法
            • 阅读getXY方法
        • 小结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档