作者:小匠

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 FlutterFinderfrom flutter_driver.flutter_driver import FlutterDriverimport uiautomator2 as u2if __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 篇挪动技术实际&干货给你思考!