乐趣区

关于flutter: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 如下所示。

图 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 FlutterFinder
from flutter_driver.flutter_driver import FlutterDriver
import 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 所示。

图 2 闲鱼 UI 自动化测试计划架构

Flutter 的元素不是齐全不能被 uiautomator2 和 facebook-wda 辨认,所以编写测试脚本时只须要解决不能被辨认的元素即可。对于有 name、label 以及 xpath 不易扭转的元素定位,咱们优先应用原生定位能力进行定位操作,其余元素则间接应用图像处理技术进行定位操作。

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

UI 自动化面临最大的问题就是——随着版本的迭代,测试脚本也须要进行一直迭代。所以在计划选型和脚本编写过程中须要思考到脚本的健壮性以及可维护性。咱们在理论脚本开发中将页面元素封装到独自的类中,并与测试逻辑拆散,从而保障前期元素迭代时只须要批改对应的页面元素即可,缩小保护老本。

图 3 脚本分层构造

闲鱼性能自动化测试的相干 UI 操作曾经应用该计划,在脚本编写时,并不需要辨别以后页面是什么类型。咱们的脚本曾经稳固运行 500+ 次,成功率超过 98%。

总结

图 4 计划比照

从图 4 能够看出,无论是 flutter driver 还是 integration test 对混合栈的反对不够成熟,然而 flutter driver 能够进行一些扩大,对于纯 Flutter 利用而言,采纳该计划可能根本满足测试需要,而 integration test 绝对没有那么成熟,对于混合栈利用的测试,可能还是须要思考混合栈的场景切换老本,应用一些 ocr 技术去做一些裁减可能老本更低,收益更大。

致谢

感激 SLM、TMQ 提供的很多底层能力反对,让咱们能够分心的做业务。

  • flutter driver(https://flutter.dev/docs/cook…)
  • integration_test(https://flutter.dev/docs/test…)

关注咱们,每周 3 篇挪动技术实际 & 干货给你思考!

退出移动版