AI 年度盘点与2025发展趋势展望,50+案例解析亮相AICon 了解详情
写点什么

Flutter UI 自动化测试技术方案选型与探索

  • 2021-06-11
  • 本文字数:2693 字

    阅读完需:约 9 分钟

Flutter UI自动化测试技术方案选型与探索

Flutter 页面无法直接使用 Native 测试工具定位元素,给自动化测试带来很多不便。虽然 Google 官方推出了 Flutter driver 和 Integration test,但是在实际使用中存在以下问题:

  • 不适用于混合栈 APP,虽然 appium 中有相关的 driver,但是无法切换环境。

  • 元素定位能力相对薄弱。

  • 依赖于 VMService,需要构建 Profile 或 Debug 包。


基于以上因素,我们并没有直接使用 Google 官方推出的工具,而是选择基于 Native 测试工具去扩展 Flutter 页面的测试能力。本文对 Flutter driver 和 Integration test 的原理和实现进行了分析,同时简单介绍闲鱼在 UI 自动化测试的尝试方案。

Flutter driver

最早接触 flutter 自动化测试时,先尝试使用 appium 框架去驱动 APP,当我们使用 inspect 功能去 dump 页面元素时发现很多元素会被合并成一个区域块,然后点击的时候只能通过 xpath 定位,想定位到某些具体的元素会比较困难,并且 xpath 其实是容易改变的,代码可维护性能力差。


因为上述原因,我们开始调研 Flutter 官方提供的测试工具——flutter driver。一开始使用该框架的时候发现它只能适用于纯 Flutter 应用,对于混合栈应用并不适应,但是它底层提供的元素定位能力或许对我们有用,于是我们对它的源码进行了剖析,该框架的原理图 1 如下所示。

null

图 1 flutter driver 原理图 


整个框架的流程交互比较简单,测试脚本在运行时,首先利用 FlutterDriver.connect()来连接 VMService 获取相关的 isolate,之后通过 websocket 来传输操作过程以及数据获取。其中测试脚本侧的所有操作都是被序列化为 json 字符串通过 websocket 传递给 ioslate 来转换为命令在 APP 侧执行,例如我们想要获取某个组件的文本内容,其最终生成的 json 结构体如下:


{    "jsonrpc":"2.0",    "id":5,    "method":"ext.flutter.driver",    "params":{        "finderType":"ByValueKey",        "keyValueString":"counter",        "keyValueType":"String",        "command":"get_text",        "isolateId":"isolates/4374098363448227"    }}
复制代码


了解上述原理后,就可以通过构造协议格式,在任何语言、测试框架下都能够去驱动 flutter 测试,所以我们对这个协议进行了封装,使用 Python 进行驱动,这样可以在使用 uiautomator2 和 facebook-wda 的基础上来测试 flutter 页面,以满足 flutter 混合栈应用的测试需求。最终的实现代码 demo 如下。


from flutter_driver.finder import FlutterFinderfrom flutter_driver.flutter_driver import FlutterDriverimport uiautomator2 as u2
if __name__ == "__main__": d = u2.connect() driver = FlutterDriver(d) if pageFlutter is True: # 如果是flutter,则使用flutter driver进行驱动 driver.connect("com.it592.flutter_app") finder = FlutterFinder.by_value_key("input") driver.tap(finder) time.sleep(1) print(driver.getText(FlutterFinder.by_value_key("counter"))) else: d(text="increase").click()
复制代码


我们尝试使用该套框架,发现其实 flutter driver 底层提供的能力相对比较薄弱,并不能完全满足我们的需求,主要问题如下:

  • 不能批量操作元素,一旦 finder 定位到的元素超过 1 个时,就会抛出异常。

  • 很多时候开发同学不写 key,元素定位也没那么方便。

  • 因为 flutter 没有 inspect 工具 dump 元素,所以只能利用结合源码去写脚本,代码维护成本比较高。

  • 官方已经放弃维护该项目,所以后续估计也不会有新功能支持。

integration_test

前面提到,flutter 官方放弃维护 Flutter driver,并推出新的测试框架 integration_test,那么这个框架会不会对混合栈应用予以支持呢,事实上试用了之后发现事情并没有我们想的那么美妙。在官方文档里有这么一句话“该软件包可在设备和模拟器上对 Flutter 代码进行自驱动测试”。


integration_test 底层的元素操作和定位还是基于 flutter_test 去驱动的,其优势主要如下:

  • 测试脚本可以使用各种 Flutter 的 API。

  • 打包 ipa、apk 后就能在 Firebase Test Lab 等设备群上运行测试,不需要额外驱动。

  • integration_test 的每个页面之间测试无关联,可以实现单个页面级别的测试。


但是由于底层元素定位和 Flutter driver 的是一致的,所以 Flutter driver 存在的问题依旧存在,同时还存在其他局限问题:

  • 测试脚本打包到 APP 中,每次修改脚本都需要重新打包。

  • 对端到端测试不够友好,需要额外函数来等待数据加载完毕。

  • 不适合全链路级别的页面测试。

  • 可扩展性弱


基于以上问题,不满足我们的使用需求,所以我们只是做了简单预研,并没有深入了解和应用。

闲鱼 UI 自动化测试方案

学习 Flutter 官方推出的相关测试框架之后,我们开始思考闲鱼 UI 自动化到底要怎么走?是站在官方的肩膀上去造轮子还是复用现有的原生自动化测试能力去扩展 Flutter 测试能力。在综合考虑投入成本以及测试脚本的维护难度后,我们选择使用图像处理技术来扩充原生自动化框架对 Flutter 页面的测试能力支持,整个测试方案架构如图 2 所示。

null

图 2 闲鱼 UI 自动化测试方案架构

 

Flutter 的元素不是完全不能被 uiautomator2 和 facebook-wda 识别,所以编写测试脚本时只需要处理不能被识别的元素即可。对于有 name、label 以及 xpath 不易改变的元素定位,我们优先使用原生定位能力进行定位操作,其他元素则直接使用图像处理技术进行定位操作。


在处理无法使用原生能力定位的元素时,我们优先使用 ocr 文字匹配来进行定位,准确率较高,不容易受分辨率的影响,对于纯图片则通过图片查找的方式进行定位。对于一些常见的元素控件例如商品卡片、价格、icon、头像等,我们构建一个训练集,使用图像分类来判断元素的类型,从而实现常用控件的定位。

UI 自动化面临最大的问题就是——随着版本的迭代,测试脚本也需要进行不断迭代。所以在方案选型和脚本编写过程中需要考虑到脚本的健壮性以及可维护性。我们在实际脚本开发中将页面元素封装到单独的类中,并与测试逻辑分离,从而保证后期元素迭代时只需要修改对应的页面元素即可,减少维护成本。


null

图 3 脚本分层结构 


闲鱼性能自动化测试的相关 UI 操作已经使用该方案,在脚本编写时,并不需要区分当前页面是什么类型。我们的脚本已经稳定运行 500+次,成功率超过 98%。

总结

null

图 4 方案对比 


从图 4 可以看出,无论是 flutter driver 还是 integration test 对混合栈的支持不够成熟,但是 flutter driver 可以进行一些扩展,对于纯 Flutter 应用而言,采用该方案能够基本满足测试需求,而 integration test 相对没有那么成熟,对于混合栈应用的测试,可能还是需要考虑混合栈的场景切换成本,使用一些 ocr 技术去做一些扩充可能成本更低,收益更大。


本文转载自:闲鱼技术(ID:XYtech_Alibaba)

原文链接:Flutter UI自动化测试技术方案选型与探索

2021-06-11 13:003809

评论

发布
暂无评论
发现更多内容

【云原生 | 从零开始学Docker】二、Docker的常用指令学习以及使用

泡泡

Docker 云计算 云原生 9月月更

融云 Flutter SDK,跨平台开发的真香之选

融云 RongCloud

flutter 跨平台开发 SDK 教程

【好一朵美丽的玫瑰花】(C++代码实现+EasyX图形化界面)

Fire_Shield

计算机视觉 9月月更 EasyX

【JavaWeb】Servlet系列——Cookie机制、乱码问题总结

胖虎不秃头

Web java; 9月月更

【JavaWeb】JSP系列——关于JSP、JSP的基础语法、利用Servlet+JSP改造项目、JSP指令、JSP九大内置对象

胖虎不秃头

Web java; 9月月更

python小知识-日志处理logging

AIWeker

Python python小知识 9月月更

极速导入elasticsearch测试数据

程序员欣宸

elasticsearch 9月月更

C++ 学习 ------cmath 头文件的源码学习 03

桑榆

c++ 源码阅读 9月月更

高性能使用索引

急需上岸的小谢

9月月更

创立一年就估值5亿美金,这个项目是怎么做到的?

One Block Community

区块链 创业 融资 defi

【精通内核】Linux内核中断控制原理源码解析

小明Java问道之路

cpu 寄存器 Linux内核 中断 9月月更

跟我以前学mybatis

楠羽

mybatis 笔记 9月月更

Web3.0 会长什么样?

掘金安东尼

前端 Web3.0 9月月更

值得收藏|三种经典的指标监控模型

穿过生命散发芬芳

9月月更 监控指标

2022-09-10:以下go语言代码输出什么?A:编译错误;B:49.0;C:49。 package main import ( “fmt“ ) func main() { ch

福大大架构师每日一题

golang 福大大 选择题

IntelliJ IDEA远程调试Elasticsearch6.1.2

程序员欣宸

elasticsearch 9月月更

【精通内核】Linux内核自旋锁实现原理与源码解析

小明Java问道之路

Linux内核 自旋锁 读锁 9月月更 写锁

【C语言深度剖析】深入理解C语言中函数的递归算法

Albert Edison

递归 C语言 函数 9月月更

架构师的十八般武艺:高并发架构

agnostic

高并发

一张图告诉你出海服务商怎么选:中国互联网出海服务商生态图谱

易观分析

报告 出海服务商

图解Kafka的服务端的网络通信模型

石臻臻的杂货铺

kafka Kafka实战 9月月更

【编程实践】一步步带你从二叉树到实现哈夫曼编码

迷彩

算法 二叉树 9月月更 哈夫曼编码 哈夫曼树

【精通内核】Linux内核抢占原理源码解析

小明Java问道之路

cpu Linux内核 中断 9月月更 内核抢占

哪些应用适合Docker化改造

阿泽🧸

Docker 9月月更

力扣260 - 只出现一次的数字||| 【哈希映射、异或位运算+分治思想】

Fire_Shield

位运算 哈希表 9月月更

【C语言】字符函数&字符串函数&内存函数(上)[进阶篇_复习专用]

Dream-Y.ocean

c c++ 9月月更

【JavaWeb】Servlet系列——session会话机制

胖虎不秃头

Web java; 9月月更

FreeRTOS记录(五、FreeRTOS任务通知)

矜辰所致

FreeRTOS 9月月更 任务通知

InnoSetup制作补丁包替换文件操作

中国好公民st

c++ qt 9月月更

HTML标准解读第一章:HTML、XML、XHTML、SGML究竟有什么区别?

水鱼兄

html 前端 HTML标准

如何用Python代码绘制赏月美景?

梦笔生花

中秋节

Flutter UI自动化测试技术方案选型与探索_架构_闲鱼技术_InfoQ精选文章