Appium Appium 做 flutter 自动化测试实践&采坑

YueChen · 2020年07月17日 · 最后由 YueChen 回复于 2021年04月02日 · 1856 次阅读

最近公司正在做 flutter sdk 的研发工作,脚本开发工作也随之而来,网上也找了很多资料对于 flutter 的自动化,貌似使用最多的还是本身 flutter_driver 驱动来做自动化测试,解决起来也踩了不少坑,这里记录一下

flutter_driver 驱动自动化测试

咱们先来看看这篇官方文档
https://flutter.dev/docs/cookbook/testing/integration/introduction

如果要用 flutter_driver 做自动化三个重要点:

  1. 代码依赖里面需要 dev_dependencies 添加依赖 flutter_driver
  2. 要在 app 代码主进程 main() 里的 runApp 之前加入 enableFlutterDriverExtension() 开启调试功能。 例如:
//void main() => runApp(MyApp());

main() {
  enableFlutterDriverExtension();
  runApp(new MyApp());
}
  1. app 启动方式需要是 profile 或者 debug 包 #打包 debug > flutter build apk --debug > flutter build ios --debug #运行 profile 或 debug > flutter run --debug > flutter run --profile

准备工作做完了,运行下看看 flutter_driver 做了啥

flutter run --profile

使用 profile 调试模式启动显示如下:

Flutter run key commands.
h Repeat this help message.
c Clear the screen
q Quit (terminate the application on the device).
An Observatory debugger and profiler on iPhone11 is available at:
http://localhost:51295

打开 web 页面:

监听了 51295 端口,看下这个端口进程是啥:

> lsof -i:51295
dart      3186 rong   17u  IPv4 0x1a4dc03ef78fcf23      0t0  TCP localhost:51298->localhost:51295 (ESTABLISHED)
dart      3186 rong   21u  IPv4 0x1a4dc03ef76f6523      0t0  TCP localhost:51300->localhost:51295 (ESTABLISHED)
iproxy    5936 rong    3u  IPv4 0x1a4dc03f0f581523      0t0  TCP localhost:51295 (LISTEN)
iproxy    5936 rong    4u  IPv6 0x1a4dc03eef247263      0t0  TCP localhost:51295 (LISTEN)
iproxy    5936 rong    5u  IPv4 0x1a4dc03ef7993f23      0t0  TCP localhost:51295->localhost:51298 (ESTABLISHED)
iproxy    5936 rong    8u  IPv4 0x1a4dc03ef05318a3      0t0  TCP localhost:51295->localhost:51300 (ESTABLISHED)

看来是 iproxy 转发了 dart 进程端口:

> ps -ax|grep iproxy
 5936 ttys010    0:00.04 /Users/rong/tools/flutter/bin/cache/artifacts/usbmuxd/iproxy 51295:58019 --udid *******62c60b38c5e5*************

iproxy 转发了 ios 设备的 58019 端口,
搜一搜 ios 控制台日志

flutter: Observatory listening on http://127.0.0.1:58019/

基本逻辑貌似搞清楚了,通过 flutter_driver 端口拼接 ws 地址转发来执行操作命令,有兴趣的可以自己抓包看看, 下面咱们看看 Appium 怎么做自动化

官方 API 地址:https://api.flutter.dev/flutter/flutter_driver/FlutterDriver/getLayerTree.html

Appium 使用 flutter-driver 驱动执行 执行自动化测试

appium 1.16 之后的版本已经有大佬写了支持 flutter_driver 驱动了 (当然 bug 不少,吐槽一下)

appium-flutter-driver 仓库地址:
https://github.com/truongsinh/appium-flutter-driver

我们写个 python demo 试试

driver = Remote('http://localhost:4723/wd/hub', dict(
    platformName='iOS',
    automationName='flutter',
    deviceName='iPhone 11',
    app="cn.rongcloud.sealbiz",
    udid="*****7b3785e8f58****",
    xcodeOrgId="***VMN****",
    xcodeSigningId="iPhone Developer",
))

print(driver.execute_script('flutter: getRenderTree'))

ws 连接地址好像和上面 web 页面挺像的,但是一直连接不上,lsof 看看端口

lsof -i:57537

啥也没有,根据上面的原理,应该是要做本地转发手机里的 flutter-driver 端口应该才能连接上,试一下看看

iproxy 57537:57537 --udid ****62c60b38c5e5**********

成功连接上了,应该是 appium-flutter-driver 端口转发问题。

知道这个问题了去看看这个仓库啥情况,并没有看到任何端口转发,fork 仓库 做了一些端口转发 bug,重连时间的修改

https://github.com/YueChen-C/appium-flutter-driver 分支:real-device

!!!必须安装了 iproxy 工具!!!

可以自己打包,也可以使用我打包好的文件,
替换掉 appium/node_modules/appium-flutter-driver/bulid

build 文件 下载
链接: https://pan.baidu.com/s/1t2uAIC3YOPL8zZ5gZT8jrA 提取码: jbma

appium-flutter-driver 还有很多功能没做,也存在很多 bug 希望小伙伴们能共同研究 flutter ~

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 18 条回复 时间 点赞

flutter 做自动化测试真的很坑,你这种还是单 Flutter 的,还有混合 Flutter 的做自动化测试就更难了。

0x88 回复

Android 还好点,至少能看到基本元素布局。iOS XCUITest 框架真的是什么元素都看不到,但官方表示这不重要😩

YueChen 回复

关键还要加启动参数 release 包怎么办

你这个是真机跑的吗?我看 FlutterDriver 还不支持真机呀!

Yu 回复

嗯,主要问题修改就是解决真机无法跑的问题

flutter 后 就不用再搞 UI 了,毕竟 debug 包很多不愿意提供的.

YueChen 回复

厉害了,我现在只看模拟器上能获取到元素,我设置到驱动名没用 Flutter,还是用的 XCUITest,我们的 App 现在是原生加 Flutter 的形式,Flutter 的代码写好后是以一个库的形式引用,光把环境配置好就弄了半天😥

Yu 回复

咦,用 XCUITest 要怎么样才能在混合工程里拿到 Flutter 元素鸭?

SpiciedCrab 回复

真机现在没法拿,模拟器可以,但是你可以是一下按照博主的来,最新版本的 Appium 已经内置来 Flutter 驱动的,但是还是等 Appium 官方支持把

小白,求助怎么在 python 中使用 Appium 和 FlutterFinder 跑起来 UI,求提供示例,如用什么方法定位,输入等这些 API 能不能拉一个交流群呀,小白好无助~ 小白微信:13433631319,小白求助~

liuxuesheng8 回复

个人建议还是不要使用 flutter_driver 来做自动化,这个驱动与 Appium 兼容做的并不是太好。
Android 使用 UiAutomator1
iOS 使用 XCUITest,iOS 怎么能查找元素,看我的这篇文章:
https://testerhome.com/topics/25388

YueChen 回复

问一下安卓用 uiautomation1 识别 flutter 稳定吗???和原生的 APP 方法是否都通用

iOS XCUITest 框架 flutter 看不见元素的问题已经解决了,

按照楼主方式,更新了 appium 里面的 appium-flutter-driver build 包,可以启动,但是元素抓取页面,一直在刷新,获取不到

16楼 已删除

appium-flutter-driver 这个驱动是没办法获取的,还是用原生的 xcuitest 和 uiautomation 吧,基本上现在也都能解决元素识别的问题了,就没必要用 appium-flutter-driver 来做驱动了

还是用原生的 xcuitest 和 uiautomation 吧

flutter 使用 appium+iOS XCUITest 框架,可以看到到元素,但是使用点击的时候获取不到,是如果在 appium 上可以看到元素,就可以使用这个元素执行吗?

driver = Remote('http://localhost:4723/wd/hub', dict(
platformName='iOS',
automationName='XCUITest',
platformVersion='13.7',
udid="00008030-000644A80285802E",
deviceName='Ly 的 iPhone',
bundleId="com.yunzhanghu.ytt4mobile",

))
driver.find_element_by_ios_predicate('value == "待装货 (7) Tab 2 of 3"').click()

Traceback (most recent call last):
File "/Users/llpan/Desktop/work/testcode/uiautotest/appium_common_utils/runner.py", line 39, in
driver.find_element_by_ios_predicate('value == "待装货 (7) Tab 2 of 3"').click()
File "/Users/llpan/Desktop/work/testcode/uiautotest/ENV/lib/python3.7/site-packages/appium/webdriver/extensions/search_context/ios.py", line 75, in find_element_by_ios_predicate
return self.find_element(by=MobileBy.IOS_PREDICATE, value=predicate_string)
File "/Users/llpan/Desktop/work/testcode/uiautotest/ENV/lib/python3.7/site-packages/appium/webdriver/webdriver.py", line 282, in find_element
return self.execute(RemoteCommand.FIND_ELEMENT, {'using': by, 'value': value})['value']
File "/Users/llpan/Desktop/work/testcode/uiautotest/ENV/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "/Users/llpan/Desktop/work/testcode/uiautotest/ENV/lib/python3.7/site-packages/appium/webdriver/errorhandler.py", line 31, in check_response
raise wde
File "/Users/llpan/Desktop/work/testcode/uiautotest/ENV/lib/python3.7/site-packages/appium/webdriver/errorhandler.py", line 26, in check_response
super().check_response(response)
File "/Users/llpan/Desktop/work/testcode/uiautotest/ENV/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: An element could not be located on the page using the given search parameters.

一般能找到就能执行,而且你这个 accessibility_id 明显是动态的,建议用 xpath 定位吧
上面图片貌似应该是这样吧:

driver.find_element_by_ios_predicate('label == "待装货 (7) Tab 2 of 3"').click()
driver.find_element_by_accessibility_id('待装货 (7) Tab 2 of 3').click()
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册