随着用户对产品体验要求越来越高,软件产品测试也越来越注重 UI 界面、兼容性的测试,特别是一些定制化很高的项目,对于 UI 界面有特定的更高要求,但是 Web 的界面布局测试,多浏览器测试,CSS/JavsScript 的重构等都成为界面测试的痛中之痛,特别是大型 Web 应用的回归测试量太大,为了有效的进行回归测试我们会进行 Unit 测试、API 测试、UI 测试等方式对产品功能性进行覆盖,但针对于 UI 界面的变动、UI 兼容性问题通常是由人工对比设计图去验证,这样既费时而且测试结果又不稳定,是否存在更高效的解决办法呢?答案是肯定的—视觉感知测试。
目前,视觉感知测试工具也不少,如 Mogotest、dpxdt、viff、bink-diff,之所以选择 dpxdt,主要是因为开源免费且完成度较高、功能较为齐全,同时,也是因为本人仅掌握了一点点的 Python 知识。现以些微实践经验总结于此,一方面作为自己的学习记录,另一方面也期望各位大神提出宝贵意见。
先上一张启动后测试效果图
为了能够实现 UI 功能自动化和 UI 界面视觉测试相关联结合,即通过 UI 自动化在预定位置截图,将图片传至 dpxdt 服务器,再由 dpxdt 进行视觉感知测试。
因此,针对原有 dpxdt 主要操作目标为:
(1)实现在本地环境(windows)启动 dpxdt 服务;
(2)在本地启动 dpxdt 服务;将原有只能以固定 json 文件作为测试用例的方式修改为输入指定测试图片目录路径即可测试,而图片名称、图片数量数量不受限制;
(3)新增图片接收接口,以获取 UI 自动化测试截取图片。
github 地址:https://github.com/bslatkin/dpxdt(建议选取"elsigh-webhook-build-ready"分支)
(1)Python2.7
安装 Python2.7,所有 dpxdt 命令执行均基于 Python2.7 环境
(2)imagemagick
dpxdt 版本 0.1.5 或 0.1.6 对应 imagemagick 版本为 6.4 之后版本,可安装 6.7 版本
下载地址:https://xiazai.xiazaiba.com/Soft/I/ImageMagick_6.7_XiaZaiBa.zip
添加安装目录内 compare.exe 文件至系统 PATH 环境变量
(3)SQLite
下载 SQLite,添加 path 环境变量,使用 sqlite3 可以进入数据库管理并显示版本信息即可
(4)phantomjs
下载 phantomjs,添加 path 环境变量,可通过命令查看版本信息
(5)进入 dpxdt 目录,使用以下命令安装第三方库依赖
pip install -r requirements.txt
pip install -e .
(1)imagemagick 不可安装最新版本,也不可能安装低于 6.4 版本,且必须配置环境变量,否则报错 “binary at path ‘compare’ does not work”;
(2)SQLite 安装成功后无需手动创建数据库 db 文件,否则配置关联该手动创建数据库时报错” unable to open database file”
(1)修改数据库配置路径
修改 dpxdt 源代码 dpxdt/server/config.py 文件中 SQLALCHEMY_DATABASE_URI 对应路径,如:SQLALCHEMY_DATABASE_URI = 'sqlite:///D:\tmp\test.db'
(2)进入 dpxdt 目录,执行./run_shell.sh
(3)依次执行以下命令关联数据库
server.db.drop_all()
server.db.create_all()
test.db 为关联数据库时创建的数据库名称,在配置的时候上级目录必须是 tmp 才能正常读取,否则会报错打开数据库失败。
(1)执行./run_combined.sh 或./run_server.sh 启动服务
(2)登录并创建新构建
(3)通过执行./run_url_pair_diff.sh 执行验证系统运行正常
如:python2 ./dpxdt/tools/url_pair_diff.py --release_server_prefix=http://localhost:5000/api --upload_build_id=1 https://www.baidu.com https://www.qq.com
注意:
(1)原有./run_url_pair_diff.sh 代码需加上 “--upload_build_id=1”(构建 id,此 id 为构建对应的数据库 id)
(2)报错找不到模块,” mportError: No module named dpxdt.client”,在对应模块添加 sys.path.append(".") 命令即可。
(1)修改 diff_my_images.py 文件中 real_main、main 函数参数 test_json_path,暂且取名为 casefile_path,并对应修改应用该参数的地方,代码如下:
def real_main(release_url=None,
casefile_path=None, #接收被测图片存放路径
upload_build_id=None,
upload_release_name=None):
"""Runs diff_my_images."""
coordinator = workers.get_coordinator()
fetch_worker.register(coordinator)
coordinator.start()
json_write(FLAGS.casefile_path) #遍历所给路径目录中所有png图片,并编写测试用例文件
tests_json_path = FLAGS.casefile_path + "/tests_case.json"#读取编写的测试用例文件
data = open(tests_json_path).read()
tests = load_tests(data)
item = DiffMyImages(
release_url,
tests,
upload_build_id,
upload_release_name,
heartbeat=workers.PrintWorkflow)
item.root = True
coordinator.input_queue.put(item)
coordinator.wait_one()
coordinator.stop()
coordinator.join()
def main(argv):
try:
argv = FLAGS(argv)
except gflags.FlagsError, e:
print '%s\nUsage: %s ARGS\n%s' % (e, sys.argv[0], FLAGS)
sys.exit(1)
assert FLAGS.release_cut_url
assert FLAGS.release_server_prefix
assert FLAGS.casefile_path
assert FLAGS.upload_build_id
if FLAGS.verbose:
logging.getLogger().setLevel(logging.DEBUG)
real_main(
release_url=FLAGS.release_cut_url,
casefile_path=FLAGS.casefile_path,
upload_build_id=FLAGS.upload_build_id,
upload_release_name=FLAGS.upload_release_name)
if __name__ == '__main__':
main(sys.argv)
(2)新增 json_write 函数,自动遍历被测图片目录中指定图片文件(此处设定为 png),并编写测试文件(json),代码如下:
def json_write(casefile_path):
filelist = os.listdir(casefile_path)
li = []
for i in filelist:
if i.endswith("png"):
with open(casefile_path+"/tests_case.json", "w") as f:
dic = {}
dic["name"] = i[:-4]
dic["run_failed"] = False
dic["image_path"] = "{0}{1}{2}".format(casefile_path, '/', i)
dic["log_path"] = "{0}{1}{2}".format(casefile_path, '/', "testlog.txt")
li.append(dic)
f.write(json.dumps(li, ensure_ascii=False))
(3)修改 flags.py 文件中设定值:
gflags.DEFINE_string(
'casefile_path', None, #将原有test_json_path修改为casefile_path
'Path to the JSON file containing the list of tests to diff.')
图片接收采用 base64 数据传递,因 dpxdt web 实现基于 flask 框架,在现有 server 中添加一个接口即可(此次添加与 frontend.py 中),代码如下:
@app.route('/savefile', methods=['PUT'])
def save():
if request.method == 'PUT':
site = request.form['site'] #site:目录名称
filename = request.form['filename'] #filename:图片存放名称
base64_data = request.form['base64_data']
basepath = os.path.dirname(__file__)
dirlist = os.listdir(os.path.join(basepath, 'static'))
if site not in dirlist:
os.mkdir(basepath + '\static\{}'.format(site))
base64_png(site, filename, base64_data)
return "更新图片成功"
def base64_png(site, filename, base64_data): #将base64转为图片,根据传参存入static下指定路径
data = base64.b64decode(base64_data)
basepath = os.path.dirname(__file__)
upload_path = os.path.join(basepath, 'static\{}'.format(site))
with open(upload_path + os.path.sep + filename + ".png", "wb") as a:
a.write(data)
在已安装 dpxdt 第三方库的情况下,执行 dpxdt 工程会导致一部分文件执行的是工程文件,一部分文件执行的是库内文件,可能造成接口加载失败。
实现测试流程大致如下:
以上,基本实现了预期目标,后续通过 UI 自动化测试,在指定页面截图后,调用 dpxdt 新增 API 传递图片至 dpxdt 服务器,再通过 shell 脚本执行进行界面元素的视觉感知测试,从 web 端即可查看结果。
参考:
视觉感知测试