一、痛点解决
1、校验页面,类似 BVT。
2、脚本的维护。
二、工具实现
1、涉及相关知识点
1)playwright(官网- https://playwright.bootcss.com/)
2)图像对比实现用到 python 库:imutils,skimage.metrics,cv2,numpy
2、设计思路
考虑到 UI 测试比较滞后,一般会在功能测试之后进行,这里便用到了已有(系统)图片的办法,
1)预期结果的处理,由于是通过系统(原)图片,这里可以通过系统(自动化/爬虫)抓取或人工截图,方式方法根据自身情况而定;
2)对图片的处理,现成的图片对比方法模型很多,这里采用的是 ssim 这种,
(2.1)修改图片大小,使对比图片与原图片大小一致,不然无法计算对比;
(2.2)计算两个灰度图像之间的结构相似度指数 [0,1],数值越高相似度越接近原图;
(2.3)找到不同点的轮廓,标识为 “不同” 的区域周围放置矩形,找到一系列区域,在区域周围放置矩形;
(2.4)分别在原图片上与对比图片上各标出差异;
(2.5)保存差异图片。
3)测试时,通过 playwright,抓取图片,即对比图片,然后与之前的(系统)预期图片进行对比,得到计算分数和差异图片,
通过分数可以分别进行判断,
等于 1 的,图片一致;
小于 1,大于等于 0.9 的,根据需要可以看下;
小于 0.9 的,分数越低越要特别注意,可能是页面有大问题。
3、代码
主要图片对比代码
import imutils
from skimage.metrics import structural_similarity as compare_ssim
import cv2
import numpy as np
class MarkDiffImg:
@staticmethod
def cv_imread(file_path):
"""
读取图片(解决路径中含有中文无法读取的问题),一般是直接cv2.imread(filea_path)
:param file_path:图片的路径
:return:
"""
cv_img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)
return cv_img
def mark_diff_img(self, result, basesnapshot_png, runningsnapshot_png, DiffSnapshot_Dir, casename, name):
"""
对比图片并标出差异,保存差异图片
:param basesnapshot_png:原始图片
:param runningsnapshot_png:对比的图片
:param DiffSnapshot_Dir:对比后存放图片的路径
:param casename:(存在的)文件夹名称
:param name:图片名称
:return:
"""
# 加载两张图片并将他们转换为灰度:
image_a = self.cv_imread(basesnapshot_png)
image_b = self.cv_imread(runningsnapshot_png)
# 修改图片大小
height, width = image_a.shape[:2]
size = (int(width * 1), int(height * 1))
image_b = cv2.resize(image_b, size, interpolation=cv2.INTER_AREA)
gray_a = cv2.cvtColor(image_a, cv2.COLOR_BGR2GRAY)
gray_b = cv2.cvtColor(image_b, cv2.COLOR_BGR2GRAY)
# 计算两个灰度图像之间的结构相似度指数:
(score, diff) = compare_ssim(gray_a, gray_b, full=True)
diff = (diff * 255).astype("uint8")
# print("SSIM:{}".format(score))
# 找到不同点的轮廓以致于我们可以在被标识为“不同”的区域周围放置矩形:
thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
# 找到一系列区域,在区域周围放置矩形:
for c in cnts:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(image_a, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.rectangle(image_b, (x, y), (x + w, y + h), (255, 0, 0), 2)
# 基础快照标出与运行时快照的差异 图片
diffsnapshot_png_a = DiffSnapshot_Dir + casename + '/' + name + '_base.png'
# 运行时快照标出与基础快照的差异 图片
diffsnapshot_png_b = DiffSnapshot_Dir + casename + '/' + name + '_running.png'
# 保存差异图片
cv2.imencode('.png', image_a)[1].tofile(diffsnapshot_png_a)
cv2.imencode('.png', image_b)[1].tofile(diffsnapshot_png_b)
# result,map类型
result["对比快照-基础快照路径"] = diffsnapshot_png_a
result["对比快照-运行时快照路径"] = diffsnapshot_png_b
return result, score
if __name__ == "__main__":
md = MarkDiffImg()
map = {}
ret, score = md.mark_diff_img(map, "../../../baseImage/企业/企业版-能源总览-用电.png", "../../../runningImage/企业版-能源管理-用电.png",
"../../../",
"image",
"测试图像对比_能源总览")
print(ret, score)
playwright 测试某模块的代码
def test_electric(login_page: Page):
"""
名称:用电
步骤:
1、打开浏览器
2、查看用电各个模块
检查点:
* 检查页面模块和数据。
"""
page = login_page
# Click a:has-text("能源总览")
page.locator("a:has-text(\"能源总览\")").click()
page.wait_for_url("https://nygl.jd.com/comp/overview")
# Click span:has-text("用电")
page.locator(selector="span:has-text(\"用电\")").click()
# 修改浏览器大小
viewport_size = {"width": 2560, "height": 1305}
page.set_viewport_size(viewport_size)
runningImage_path = "../../../runningImage/企业版-能源管理-用电.png"
page.screenshot(path=runningImage_path)
mdi = MarkDiffImg()
baseImage_path = "../../../baseImage/企业/企业版-能源总览-用电.png"
map = {}
retImage, score = mdi.mark_diff_img(map, baseImage_path, runningImage_path, "../../../",
"diffImage",
"测试图像对比_企业版-能源总览-用电")
if score == 1.0:
assert True
print("展示的页面与数据一致")
elif score >= 0.9 and score != 1.0:
print("展示的页面与数据基本一致,score: ", score)
assert True
else:
print("展示的页面与数据部分一致,score: ", score)
assert False
4、结果