Flutter UI自动化测试技术方案选型与探索
ztj100 2024-10-30 05:10 49 浏览 0 评论
作者:小匠
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如下所示。
整个框架的流程交互比较简单,测试脚本在运行时,首先利用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所示。
Flutter的元素不是完全不能被uiautomator2和facebook-wda识别,所以编写测试脚本时只需要处理不能被识别的元素即可。对于有name、label以及xpath不易改变的元素定位,我们优先使用原生定位能力进行定位操作,其他元素则直接使用图像处理技术进行定位操作。
在处理无法使用原生能力定位的元素时,我们优先使用ocr文字匹配来进行定位,准确率较高,不容易受分辨率的影响,对于纯图片则通过图片查找的方式进行定位。对于一些常见的元素控件例如商品卡片、价格、icon、头像等,我们构建一个训练集,使用图像分类来判断元素的类型,从而实现常用控件的定位。
UI自动化面临最大的问题就是——随着版本的迭代,测试脚本也需要进行不断迭代。所以在方案选型和脚本编写过程中需要考虑到脚本的健壮性以及可维护性。我们在实际脚本开发中将页面元素封装到单独的类中,并与测试逻辑分离,从而保证后期元素迭代时只需要修改对应的页面元素即可,减少维护成本。
闲鱼性能自动化测试的相关UI操作已经使用该方案,在脚本编写时,并不需要区分当前页面是什么类型。我们的脚本已经稳定运行500+次,成功率超过98%。
总结
从图4可以看出,无论是flutter driver还是integration test对混合栈的支持不够成熟,但是flutter driver可以进行一些扩展,对于纯Flutter应用而言,采用该方案能够基本满足测试需求,而integration test相对没有那么成熟,对于混合栈应用的测试,可能还是需要考虑混合栈的场景切换成本,使用一些ocr技术去做一些扩充可能成本更低,收益更大。
致谢
感谢SLM、TMQ提供的很多底层能力支持,让我们可以专心的做业务。
- flutter driver(https://flutter.dev/docs/cookbook/testing/integration/introduction)
- integration_test(https://flutter.dev/docs/testing/integration-tests)
关注我们,每周 3 篇移动技术实践&干货给你思考!
相关推荐
- 其实TensorFlow真的很水无非就这30篇熬夜练
-
好的!以下是TensorFlow需要掌握的核心内容,用列表形式呈现,简洁清晰(含表情符号,<300字):1.基础概念与环境TensorFlow架构(计算图、会话->EagerE...
- 交叉验证和超参数调整:如何优化你的机器学习模型
-
准确预测Fitbit的睡眠得分在本文的前两部分中,我获取了Fitbit的睡眠数据并对其进行预处理,将这些数据分为训练集、验证集和测试集,除此之外,我还训练了三种不同的机器学习模型并比较了它们的性能。在...
- 机器学习交叉验证全指南:原理、类型与实战技巧
-
机器学习模型常常需要大量数据,但它们如何与实时新数据协同工作也同样关键。交叉验证是一种通过将数据集分成若干部分、在部分数据上训练模型、在其余数据上测试模型的方法,用来检验模型的表现。这有助于发现过拟合...
- 深度学习中的类别激活热图可视化
-
作者:ValentinaAlto编译:ronghuaiyang导读使用Keras实现图像分类中的激活热图的可视化,帮助更有针对性...
- 超强,必会的机器学习评估指标
-
大侠幸会,在下全网同名[算法金]0基础转AI上岸,多个算法赛Top[日更万日,让更多人享受智能乐趣]构建机器学习模型的关键步骤是检查其性能,这是通过使用验证指标来完成的。选择正确的验证指...
- 机器学习入门教程-第六课:监督学习与非监督学习
-
1.回顾与引入上节课我们谈到了机器学习的一些实战技巧,比如如何处理数据、选择模型以及调整参数。今天,我们将更深入地探讨机器学习的两大类:监督学习和非监督学习。2.监督学习监督学习就像是有老师的教学...
- Python 模型部署不用愁!容器化实战,5 分钟搞定环境配置
-
你是不是也遇到过这种糟心事:花了好几天训练出的Python模型,在自己电脑上跑得顺顺当当,一放到服务器就各种报错。要么是Python版本不对,要么是依赖库冲突,折腾半天还是用不了。别再喊“我...
- 神经网络与传统统计方法的简单对比
-
传统的统计方法如...
- 自回归滞后模型进行多变量时间序列预测
-
下图显示了关于不同类型葡萄酒销量的月度多元时间序列。每种葡萄酒类型都是时间序列中的一个变量。假设要预测其中一个变量。比如,sparklingwine。如何建立一个模型来进行预测呢?一种常见的方...
- 苹果AI策略:慢哲学——科技行业的“长期主义”试金石
-
苹果AI策略的深度原创分析,结合技术伦理、商业逻辑与行业博弈,揭示其“慢哲学”背后的战略智慧:一、反常之举:AI狂潮中的“逆行者”当科技巨头深陷AI军备竞赛,苹果的克制显得格格不入:功能延期:App...
- 时间序列预测全攻略,6大模型代码实操
-
如果你对数据分析感兴趣,希望学习更多的方法论,希望听听经验分享,欢迎移步宝藏公众号...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)