在进行UI自动化测试的时候,有些元素难以匹配,需要采用图片比对的方式找到并操作。
阅读一下AirTest的代码来借鉴一下
下载一个AirtestIDE。下载地址:https://airtest.netease.com/
touch
并框选一个图片pip install airtest
# -*- 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()
完成了元素的点击操作
@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
所以把这段代码简化一下
pos = loop_find(v, timeout=20)
G.DEVICE.touch(pos, **kwargs)
使用了loop_find
找到了pos
然后touch
了一下
根据编写Selenium
代码的经验,大概可以猜测G.DEVICE
是一个类似driver
对象的操作对象
阅读它的代码也可以看出来,不过不看了
@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)
简化一下
screen = G.DEVICE.snapshot(filename=None, quality=ST.SNAPSHOT_QUALITY)
match_pos = query.match_in(screen)
这里进行了一次屏幕截图,然后调用了match_in
方法
这个方法进入了Template
类了,对外除了实例化应该就用了这个类中的这个方法
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
简化
match_result = self._cv_match(screen)
focus_pos = TargetPos().getXY(match_result, self.target_pos)
@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
简化一下
上半部分
ori_image = self._imread()
image = self._resize_image(ori_image, screen, ST.RESIZE_METHOD)
ori_image
:读取目标图片
在截取tpl1648886223193.png
图片文件的时候 IDE把要定位的图片+定位时的屏幕分辨率当做参数传入了Template
类中
这时就可以根据(要定位的图片+要定位图片截图时候的屏幕分辨率)+ 当前屏幕的分辨率 + 算法(ST.RESIZE_METHOD
) => 缩放后的当前屏幕图片image
下半部分
for method in ST.CVSTRATEGY:
func = MATCHING_METHODS.get(method, None)
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,
}
ret = self._try_match(func, image, screen, xxx)
遍历4种图片比对算法
,得到ret
在math_in方法里面有一句
G.LOGGING.debug("match result: %s", match_result)
也就是这个结果会被打印出来。查看一下AirtestIDE
的日志
[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}
该方法是获得目标的不同位置的坐标
从这里可以看出来result
就是匹配到的要点击的图片的中间
rectangle
则是要点击图片的四个角的坐标
到此我们可以通过上述代码来实现获取目标位置坐标
接下来把他们拷贝出来整理整理就可以了