Windows应用自动测试:图片比对功能详解
最编程
2024-02-23 20:36:14
...
windows 应用自动化测试--图像对比
一.原理和框架结构
- Sikuli 是通过图像识别在应用的自动化的,完全的黑盒,适用于很多非标准话应用的测试
二.学习成本和业务匹配程度
- 框架结构:python+sikulijar包+cv2+jpype+unittest+HTMLTestRunner.py
- 业务匹配程度:cpos是非标准win应用,调研发现坐标识识别和图像识别是业界常用的
方法
- 学习成本:很低,截图和调用简单api
- 缺点:执行速度相对慢,无法支持跨分辨率,无法提供丰富的断言
-
测试结果展示:
三.核心api封装
import logging
import os
import time
from jpype import *
from UIlib.logger import Logger
from UIlib import commen
'''
sikuli api封装
'''
loger=Logger('sikuliApi')
class sikuliApi(object):
def __init__(self):
self.root_path = os.path.dirname(os.path.split(os.path.realpath(__file__))[0])
self.pos_type=pos_type
try:
sc=JClass("org.sikuli.script.Screen")
self.Screen = sc() # 窗口包
self.Region = JClass("org.sikuli.script.Region") # 窗口区域识别包
self.key = JClass("org.sikuli.script.Key") # 键盘和鼠标操作包
self.Pattern = JClass('org.sikuli.script.Pattern') # 识别粒度配置包
self.FindFailed = JClass('org.sikuli.script.FindFailed') # 识别异常包
except Exception as e:
loger.logger.error("sikuli 包加载错误:{}".format(e))
exit()
def d_click(self,img_name,lan,times=0.5,casename=None,is_running=0):
'''非严格匹配鼠标单击'''
target_img = self.get_img_path(lan=lan, img_name=img_name) # 获取图片路径
try:
if os.path.exists(target_img) is False:
loger.logger.error('target_img is not exists:{}'.format(target_img))
self.Screen.click(target_img)
time.sleep(times)
def click(self,img_name,lan,times=0.5,case_name=None,is_running=2,msg=None):
'''鼠标单击'''
target_img=self.get_img_path(lan=lan,img_name=img_name)#获取图片路径
loger.logger.info('点击:{},{}'.format(img_name,msg))
try:
if os.path.exists(target_img) is False:
loger.logger.error('点击的图片不存在:{}'.format(target_img))
if self.is_exists(img_name=img_name,lan=lan):
self.Screen.click(self.Pattern(target_img).exact())
else:
loger.logger.info('屏幕上没有找到图片:{}'.format(img_name))
#self.Screen.click(target_img) #宽松模式
time.sleep(times)
img_tag=is_running,pos_type=self.pos_type)
except Exception as e :
loger.logger.error("click 异常:{}".format(e))
def double_click(self,lan,img_name,times=0.5,case_name=None,is_running=0):
'''鼠标双击'''
target_img = self.get_img_path(lan=lan, img_name=img_name) # 获取图片路径
loger.logger.info('点击:{}'.format(img_name))
try:
if os.path.exists(target_img) is False:
loger.logger.error('点击的图片不存在:{}'.format(target_img))
if self.is_exists(img_name=img_name, lan=lan):
self.Screen.doubleClick(self.Pattern(target_img).exact())
else:
raise Exception('屏幕上没有找到图片:{}'.format(img_name))
# self.Screen.click(target_img) #宽松模式
time.sleep(times)
except Exception as e:
loger.logger.error("click 异常:{}".format(e))
def enter_key(self,key='ENTER',times=0.1,casename=None,is_running=0):
'''键盘操作,暂时未扩展,只支持enter键'''
loger.logger.info('执行:{}'.format(key))
try:
if key=='ENTER':
self.Screen.type(self.key.ENTER)
elif key=='backspace':
self.Screen.type(self.key.BACKSPACE)
time.sleep(times)
except Exception as e:
loger.logger.error("enter_key 异常:{}".format(e))
def input_str(self,words:str,times=1,casename=None,is_running=0,msg=None):
'''输入字符串'''
loger.logger.info('执行输入:{},{}'.format(words,msg))
try:
self.Screen.type(str(words))
time.sleep(times)
except Exception as e:
loger.logger.error("input_str 异常:{}".format(e))
def is_exists(self,lan,img_name):
'''判断图片是否存在'''
target_img = self.get_img_path(lan=lan, img_name=img_name) # 获取图片路径
try:
if os.path.exists(target_img) is False:
loger.logger.error('img is not exists:{}'.format(target_img))
return self.Screen.exists(target_img)
#return self.Screen.exists(self.Pattern(target_img).exact())
except Exception as e:
loger.logger.error("is_exists 异常:{}".format(e))
def do_screenshots(self,lan,img_name,img_tag=0,is_Shelter=0):
target_img = self.get_img_path(lan=lan, img_name=img_name)
if os.path.exists(target_img) is False:
loger.logger.error('img is not exists:{}'.format(target_img))
else:
if self.is_exists(lan=lan,img_name=img_name):
commen.get_img(img_name=img_name,img_tag=img_tag,is_Shelter=is_Shelter,pos_type=self.pos_type)
def wait_until_imgExist(self,img_name,lan,wait_number=20):
n=1
while n <wait_number:
ret=self.is_exists(lan=lan,img_name=img_name)
loger.logger.info('{} 识别结果:{}'.format(img_name,ret))
if ret:
return True
else:
loger.logger.info('识别重试:{}'.format(n))
time.sleep(0.1)
n=n+1
if n>=(wait_number-1):
loger.logger.info('识别重试结束')
return False
def Switch_screen(self,screen_type):
''' 1:大屏幕;0:小屏幕'''
if screen_type==1:
Screen = self.Screen.getScreen(1)
elif screen_type==0:
Screen = self.Screen.getScreen(0)
else:
raise BaseException('屏幕选择错误:{}'.format(screen_type))
self.Screen=Screen
if __name__=='__main__':
pass
# startdemoVm()
# api = sikuliApi(pos_type='df')
# api = sikuliApi(pos_type='df')
# api.enter_key()
#
# shutdoemVm()
- 框架结构:python+sikulijar包+cv2+jpype+unittest+HTMLTestRunner.py
- 业务匹配程度:cpos是非标准win应用,调研发现坐标识识别和图像识别是业界常用的
方法 - 学习成本:很低,截图和调用简单api
- 缺点:执行速度相对慢,无法支持跨分辨率,无法提供丰富的断言
-
测试结果展示:
三.核心api封装
import logging
import os
import time
from jpype import *
from UIlib.logger import Logger
from UIlib import commen
'''
sikuli api封装
'''
loger=Logger('sikuliApi')
class sikuliApi(object):
def __init__(self):
self.root_path = os.path.dirname(os.path.split(os.path.realpath(__file__))[0])
self.pos_type=pos_type
try:
sc=JClass("org.sikuli.script.Screen")
self.Screen = sc() # 窗口包
self.Region = JClass("org.sikuli.script.Region") # 窗口区域识别包
self.key = JClass("org.sikuli.script.Key") # 键盘和鼠标操作包
self.Pattern = JClass('org.sikuli.script.Pattern') # 识别粒度配置包
self.FindFailed = JClass('org.sikuli.script.FindFailed') # 识别异常包
except Exception as e:
loger.logger.error("sikuli 包加载错误:{}".format(e))
exit()
def d_click(self,img_name,lan,times=0.5,casename=None,is_running=0):
'''非严格匹配鼠标单击'''
target_img = self.get_img_path(lan=lan, img_name=img_name) # 获取图片路径
try:
if os.path.exists(target_img) is False:
loger.logger.error('target_img is not exists:{}'.format(target_img))
self.Screen.click(target_img)
time.sleep(times)
def click(self,img_name,lan,times=0.5,case_name=None,is_running=2,msg=None):
'''鼠标单击'''
target_img=self.get_img_path(lan=lan,img_name=img_name)#获取图片路径
loger.logger.info('点击:{},{}'.format(img_name,msg))
try:
if os.path.exists(target_img) is False:
loger.logger.error('点击的图片不存在:{}'.format(target_img))
if self.is_exists(img_name=img_name,lan=lan):
self.Screen.click(self.Pattern(target_img).exact())
else:
loger.logger.info('屏幕上没有找到图片:{}'.format(img_name))
#self.Screen.click(target_img) #宽松模式
time.sleep(times)
img_tag=is_running,pos_type=self.pos_type)
except Exception as e :
loger.logger.error("click 异常:{}".format(e))
def double_click(self,lan,img_name,times=0.5,case_name=None,is_running=0):
'''鼠标双击'''
target_img = self.get_img_path(lan=lan, img_name=img_name) # 获取图片路径
loger.logger.info('点击:{}'.format(img_name))
try:
if os.path.exists(target_img) is False:
loger.logger.error('点击的图片不存在:{}'.format(target_img))
if self.is_exists(img_name=img_name, lan=lan):
self.Screen.doubleClick(self.Pattern(target_img).exact())
else:
raise Exception('屏幕上没有找到图片:{}'.format(img_name))
# self.Screen.click(target_img) #宽松模式
time.sleep(times)
except Exception as e:
loger.logger.error("click 异常:{}".format(e))
def enter_key(self,key='ENTER',times=0.1,casename=None,is_running=0):
'''键盘操作,暂时未扩展,只支持enter键'''
loger.logger.info('执行:{}'.format(key))
try:
if key=='ENTER':
self.Screen.type(self.key.ENTER)
elif key=='backspace':
self.Screen.type(self.key.BACKSPACE)
time.sleep(times)
except Exception as e:
loger.logger.error("enter_key 异常:{}".format(e))
def input_str(self,words:str,times=1,casename=None,is_running=0,msg=None):
'''输入字符串'''
loger.logger.info('执行输入:{},{}'.format(words,msg))
try:
self.Screen.type(str(words))
time.sleep(times)
except Exception as e:
loger.logger.error("input_str 异常:{}".format(e))
def is_exists(self,lan,img_name):
'''判断图片是否存在'''
target_img = self.get_img_path(lan=lan, img_name=img_name) # 获取图片路径
try:
if os.path.exists(target_img) is False:
loger.logger.error('img is not exists:{}'.format(target_img))
return self.Screen.exists(target_img)
#return self.Screen.exists(self.Pattern(target_img).exact())
except Exception as e:
loger.logger.error("is_exists 异常:{}".format(e))
def do_screenshots(self,lan,img_name,img_tag=0,is_Shelter=0):
target_img = self.get_img_path(lan=lan, img_name=img_name)
if os.path.exists(target_img) is False:
loger.logger.error('img is not exists:{}'.format(target_img))
else:
if self.is_exists(lan=lan,img_name=img_name):
commen.get_img(img_name=img_name,img_tag=img_tag,is_Shelter=is_Shelter,pos_type=self.pos_type)
def wait_until_imgExist(self,img_name,lan,wait_number=20):
n=1
while n <wait_number:
ret=self.is_exists(lan=lan,img_name=img_name)
loger.logger.info('{} 识别结果:{}'.format(img_name,ret))
if ret:
return True
else:
loger.logger.info('识别重试:{}'.format(n))
time.sleep(0.1)
n=n+1
if n>=(wait_number-1):
loger.logger.info('识别重试结束')
return False
def Switch_screen(self,screen_type):
''' 1:大屏幕;0:小屏幕'''
if screen_type==1:
Screen = self.Screen.getScreen(1)
elif screen_type==0:
Screen = self.Screen.getScreen(0)
else:
raise BaseException('屏幕选择错误:{}'.format(screen_type))
self.Screen=Screen
if __name__=='__main__':
pass
# startdemoVm()
# api = sikuliApi(pos_type='df')
# api = sikuliApi(pos_type='df')
# api.enter_key()
#
# shutdoemVm()
import logging
import os
import time
from jpype import *
from UIlib.logger import Logger
from UIlib import commen
'''
sikuli api封装
'''
loger=Logger('sikuliApi')
class sikuliApi(object):
def __init__(self):
self.root_path = os.path.dirname(os.path.split(os.path.realpath(__file__))[0])
self.pos_type=pos_type
try:
sc=JClass("org.sikuli.script.Screen")
self.Screen = sc() # 窗口包
self.Region = JClass("org.sikuli.script.Region") # 窗口区域识别包
self.key = JClass("org.sikuli.script.Key") # 键盘和鼠标操作包
self.Pattern = JClass('org.sikuli.script.Pattern') # 识别粒度配置包
self.FindFailed = JClass('org.sikuli.script.FindFailed') # 识别异常包
except Exception as e:
loger.logger.error("sikuli 包加载错误:{}".format(e))
exit()
def d_click(self,img_name,lan,times=0.5,casename=None,is_running=0):
'''非严格匹配鼠标单击'''
target_img = self.get_img_path(lan=lan, img_name=img_name) # 获取图片路径
try:
if os.path.exists(target_img) is False:
loger.logger.error('target_img is not exists:{}'.format(target_img))
self.Screen.click(target_img)
time.sleep(times)
def click(self,img_name,lan,times=0.5,case_name=None,is_running=2,msg=None):
'''鼠标单击'''
target_img=self.get_img_path(lan=lan,img_name=img_name)#获取图片路径
loger.logger.info('点击:{},{}'.format(img_name,msg))
try:
if os.path.exists(target_img) is False:
loger.logger.error('点击的图片不存在:{}'.format(target_img))
if self.is_exists(img_name=img_name,lan=lan):
self.Screen.click(self.Pattern(target_img).exact())
else:
loger.logger.info('屏幕上没有找到图片:{}'.format(img_name))
#self.Screen.click(target_img) #宽松模式
time.sleep(times)
img_tag=is_running,pos_type=self.pos_type)
except Exception as e :
loger.logger.error("click 异常:{}".format(e))
def double_click(self,lan,img_name,times=0.5,case_name=None,is_running=0):
'''鼠标双击'''
target_img = self.get_img_path(lan=lan, img_name=img_name) # 获取图片路径
loger.logger.info('点击:{}'.format(img_name))
try:
if os.path.exists(target_img) is False:
loger.logger.error('点击的图片不存在:{}'.format(target_img))
if self.is_exists(img_name=img_name, lan=lan):
self.Screen.doubleClick(self.Pattern(target_img).exact())
else:
raise Exception('屏幕上没有找到图片:{}'.format(img_name))
# self.Screen.click(target_img) #宽松模式
time.sleep(times)
except Exception as e:
loger.logger.error("click 异常:{}".format(e))
def enter_key(self,key='ENTER',times=0.1,casename=None,is_running=0):
'''键盘操作,暂时未扩展,只支持enter键'''
loger.logger.info('执行:{}'.format(key))
try:
if key=='ENTER':
self.Screen.type(self.key.ENTER)
elif key=='backspace':
self.Screen.type(self.key.BACKSPACE)
time.sleep(times)
except Exception as e:
loger.logger.error("enter_key 异常:{}".format(e))
def input_str(self,words:str,times=1,casename=None,is_running=0,msg=None):
'''输入字符串'''
loger.logger.info('执行输入:{},{}'.format(words,msg))
try:
self.Screen.type(str(words))
time.sleep(times)
except Exception as e:
loger.logger.error("input_str 异常:{}".format(e))
def is_exists(self,lan,img_name):
'''判断图片是否存在'''
target_img = self.get_img_path(lan=lan, img_name=img_name) # 获取图片路径
try:
if os.path.exists(target_img) is False:
loger.logger.error('img is not exists:{}'.format(target_img))
return self.Screen.exists(target_img)
#return self.Screen.exists(self.Pattern(target_img).exact())
except Exception as e:
loger.logger.error("is_exists 异常:{}".format(e))
def do_screenshots(self,lan,img_name,img_tag=0,is_Shelter=0):
target_img = self.get_img_path(lan=lan, img_name=img_name)
if os.path.exists(target_img) is False:
loger.logger.error('img is not exists:{}'.format(target_img))
else:
if self.is_exists(lan=lan,img_name=img_name):
commen.get_img(img_name=img_name,img_tag=img_tag,is_Shelter=is_Shelter,pos_type=self.pos_type)
def wait_until_imgExist(self,img_name,lan,wait_number=20):
n=1
while n <wait_number:
ret=self.is_exists(lan=lan,img_name=img_name)
loger.logger.info('{} 识别结果:{}'.format(img_name,ret))
if ret:
return True
else:
loger.logger.info('识别重试:{}'.format(n))
time.sleep(0.1)
n=n+1
if n>=(wait_number-1):
loger.logger.info('识别重试结束')
return False
def Switch_screen(self,screen_type):
''' 1:大屏幕;0:小屏幕'''
if screen_type==1:
Screen = self.Screen.getScreen(1)
elif screen_type==0:
Screen = self.Screen.getScreen(0)
else:
raise BaseException('屏幕选择错误:{}'.format(screen_type))
self.Screen=Screen
if __name__=='__main__':
pass
# startdemoVm()
# api = sikuliApi(pos_type='df')
# api = sikuliApi(pos_type='df')
# api.enter_key()
#
# shutdoemVm()
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
推荐阅读
-
旷视天元开源图像比对工具 MegSpot,助力图像算法研发 - 1.多样化图像比对:可提供叠加比对、拖拽比对等多种比对方式,支持缩放、移动等同步操作,并可生成 GIF 保存比对结果。2. 2.专业呈现:支持像素级图像查看、图像直方图、RGB 查看;支持预览亮度、对比度、饱和度、灰度等指标。3. 视频对比:Cognizant Megapixel 可提供多种图像对比方法,如拖放对比等。 3.视频对比:除了支持视屏的所有图像对比功能外,CCTV MegSpot 还支持同步回放、回放暂停和快进、回放速度设置等功能。 4.跨平台支持:CCTV MegSpot 提供对 Mac、Linux 和 Windows 系统的跨平台支持,借助 Electron 框架,可以低成本完成跨平台应用的开发,并保证各平台体验的一致性。 此外,央视网MegSpot支持跨平台自动更新和数据持久化,确保用户体验的连续性,并支持中、英、日三种语言:MegSpot为大尺寸图像文件的对比提供了本地解决方案。 MegSpot 是一种用于比较大型图像文件的本地解决方案。
-
Windows应用自动测试:图片比对功能详解
-
用Flutter打造Windows应用的版本更新功能:第一部分 - 详解