本文主要参考以下博文,感谢其作者的总结分享。
https://www.cnblogs.com/ybcao/p/5463030.html
https://www.cnblogs.com/fnng/p/4881102.html
背景:
做CS架构的客户端应用程序UI自动化测试时,需要用图标的状态来判断程序运行的结果。图标的控件类型为Image。所以需要通过判断图标所在的图片来实现自动化用例中的断言。
解决方案:
首先,需要定位到目标控件的坐标,然后截图,再将截图与期望图片进行比较。
这里主要需要解决的3个点:
- 获取图片控件坐标
- 截图
- 比较图片
经过查询,python系现有模块中pywinauto、Pillow模块即可实现上述功能。
其中pywinauto可以获取控件坐标,Pillow模块可以根据坐标截图,并比较指定图片。
pywinauto实现指定控件的坐标获取
这里主要利用pywinauto框架提供print_control_identifiers()方法,该方法将输出应用程序的控件信息,默认输出到标准输出中,但为了对其处理,重定向标准输出,使得控件信息写入到指定列表内。
import sys
# TempStdoutArea对象为为重定向标准输出准备的空间,以列表形式存在
class TempStdoutArea:
def __init__(self):
self.buffer = []
def write(self, *args, **kwargs):
self.buffer.append(args)
# 实现获取指定控件坐标的对象
class GetControlCoord:
# app为 pywinauto框架实例化的Application对象
def __init__(self, app):
self.app = app
# 获取指定控件坐标的方法,control参数传入指定控件
def get_coord(self, control):
# 重定向标准输出,将原本的标准输出信息写入自定义的空间内,以获取控件信息
stdout = sys.stdout
sys.stdout = TempStdoutArea()
# pywinauto框架提供的print_control_identifiers()方法,可以打印出应用程序的控件信息,其中就包含控件坐标
self.app.print_control_identifiers()
# 将控件信息转移到control_identifiers,并还原标准输出
control_identifiers, sys.stdout = sys.stdout, stdout
#print(control_identifiers.buffer)
all_coord = []
# 遍历控件信息,获取指定控件的坐标
for a_control_identifier in control_identifiers.buffer:
#print(a_control_identifier)
#print(a_control_identifier[0])
a_control_identifier = a_control_identifier[0]
if a_control_identifier.find(control) > -1:
#print(a_control_identifier)
a_coord = []
str_coord = a_control_identifier[a_control_identifier.find('(')+1 : a_control_identifier.find(')')].split(',')
#print(str_coord)
for i in str_coord:
num = int(i.strip()[1:])
a_coord.append(num)
all_coord.append(a_coord)
return all_coord
PIL实现截图,图片比较
这里主要运用该模块提供的方法,相对win32API,其封装易用性非常好。
from PIL import ImageGrab
from PIL import Image
from PIL import ImageChops
import math
import operator
from functools import reduce
# save_img 截图保存命名,coord以元组形式传入控件坐标
def capture_image(coord = (10, 929, 122, 1070), save_img = 'default.png'):
im = ImageGrab.grab(coord)
# 参数 保存截图文件的路径
im.save(save_img)
# 比较图像是否相同的方法1
# 如果返回值是None代表图片相同,如果不是,图片不相同
def compare_image(image_1, image_2):
image_1 = Image.open(image_1)
image_2 = Image.open(image_2)
return ImageChops.difference(image_1,image_2).getbbox()
# 比较图像是否相同的方法2
# 如果返回值大于0,则图片不相同
def compare_image_01(image_1, image_2):
image_1 = Image.open(image_1)
image_2 = Image.open(image_2)
h1 = image_1.histogram()
h2 = image_2.histogram()
return math.sqrt(reduce(operator.add, list(map(lambda a,b: (a-b)**2, h1, h2)))/ len(h1))
最后
以上,就是CS架构的客户端应用程序,对于图片的自动化测试方法