ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

云真机替代真机与模拟器:安卓自动化测试环境新选择

云真机替代真机与模拟器:安卓自动化测试环境新选择 先交代一个背景我最近在做公司一个工具类App的回归测试。手上一台老安卓机跑一会儿测试就发热降频脚本时不时超时桌面上的模拟器倒是快可一碰到定位、推送、扫码这类依赖真实系统能力的场景就露馅。团队里另一个同事更惨入职三个月光修设备墙上的真机就花了两周——不是USB口松动就是手机锁屏密码忘了或者是某个厂商的ROM又偷偷杀了后台进程。这时候我们才开始认真排查一个问题除了自购真机和本地模拟器到底还有什么靠谱的安卓自动化测试环境答案就是标题里这个方向云端设备。更具体点说是不需要自己养设备墙、又能直接跑Appium脚本的云真机/云设备平台。这篇文章我把目前主流的替代方案整理了一遍然后拿QTPHONE做了几轮完整的自动化测试实测把连接方式、兼容性、踩坑点、适合跑什么类型的用例都讲清楚。如果你也在纠结测试环境到底怎么搭这篇应该能帮你省不少调研时间。1. 为什么真机和模拟器越来越不够用三个正在发生的现实问题先说真机。很多人觉得真机是最接近用户的环境这没错但真机并不等于最可靠的自动化测试环境。我自己维护过一段时间的测试真机最头疼的其实不是手机本身而是它衍生出来的一堆杂事。第一是设备墙的维护成本。一台机器要跑自动化得保证它一直插着电、连着USB、屏幕常亮、不锁屏、不被系统更新打断。Android设备用久了还会出现USB调试授权失效、ADB端口被占用、电池鼓包、数据线接触不良这类问题。团队里如果有5台设备基本就要有一个人兼职设备管理员每周固定时间重启机器、清理缓存、重装应用。这活儿说大不大但非常消磨耐心而且完全不属于测试技术本身。第二是机型覆盖永远跟不上。你手上只有3台Android设备可线上用户里可能有几百种机型组合。安卓系统版本从8.0到15厂商定制ROM从MIUI到ColorOS同一个WebView页面在不同机型上渲染效果可能完全不同。用真机做覆盖要么靠众测平台要么就只能接受测了主要机型、但不敢保证全量兼容的现状。第三是CI集成非常别扭。自动化测试一旦要跑在持续集成流水线里就需要设备随时在线、支持并发分配、跑完能自动清理环境。自建设备墙要做到这三点得配套机房、USB HUB、远程控制服务投入不小而且设备一旦被某个人占着调试其他任务就得排队。再看模拟器这边。模拟器的优势是资源灵活、快照恢复快、可以在同一台机器上开多个实例。但它的短板也相当明确。一个是模拟器跑不出真实硬件行为。传感器数据是伪造的GPS信号是伪造的键盘和交互方式也和真机有差异。你做自动化测试如果用例本身不涉及这些能力模拟器完全够用可一旦涉及相机扫码、NFC、蓝牙、重力感应、通话状态模拟器就很容易假阳性——模拟环境里跑通了真机上却挂了。另一个问题是部分App对模拟器环境有检测。尤其是涉及支付、金融、游戏、反作弊的App会通过Build.FINGERPRINT、CPU架构、传感器列表等特征识别模拟器环境检测到就直接退出或静默降级。这导致模拟器上你的UI自动化连首页都进不去更别提后面的业务流程。换句话说真机的痛点在于成本和资源分配模拟器的痛点在于环境保真度。这两类问题催生了第三类方案——把设备放到云端通过网络远程调用或以集群方式对外提供服务。这也就是替代真机和模拟器的安卓自动化测试方案最核心的动机。2. 现在市面上主要的替代方案到底有哪几条路线我大致把当前能替代自购真机和本地模拟器的方案分成四类。每一类都有自己的适用边界别只听厂商宣传关键要看你测试的目标是什么。2.1 自建设备集群开源STF方案STFSmartphone Test Farm是当年比较成熟的开源方案。它的思路很直接用一组USB HUB把几十台真机接在一台服务器上浏览器里能看到每台设备的实时画面可以对设备做远程操作、安装App、执行ADB命令。这套方案最大的优点是完全可控设备都在自己手里数据不出内网适合对隐私要求高的项目。缺点也显而易见你得有一块物理空间放设备墙得处理散热、供电、走线STF本身的部署和维护有学习成本设备种类越多兼容性问题越复杂。我身边真正把STF跑起来的团队基本上都得有一个懂Linux运维的人专门负责这个环境。如果团队只有几个测试开发光设备墙的搬运和连接就会劝退大部分人。2.2 商业云真机大厂云测平台这类国内几家大厂都提供在线真机测试服务基本逻辑是平台维护一个真实设备集群用户通过Web界面或API选择目标机型在云端执行手工测试或自动化脚本。这类平台的优势是机型覆盖广几乎能覆盖主流Android厂商和版本不用自己养设备按次或按时长付费部分平台还带崩溃采集、性能报告等附加值。局限在于跨内网的数据链路不一定允许计费策略在持续集成的场景下成本不可控一些深度依赖内部网络或内部签名的测试包不一定能顺利上传执行。2.3 容器化的安卓虚拟机环境第三种路线是Docker里跑Android系统比如docker-android这类开源项目或者Genymotion的云方案。它介于模拟器和真机之间比本地模拟器更容易批量部署也支持在K8s集群里动态调度适合大规模并行执行UI自动化用例。这类方案最大的问题是它本质上还是模拟器只是换了一个容器化的运行形态。前面说的传感器失效、反模拟器检测这些问题依然存在。如果你的用例只是普通业务路径的冒烟测试容器化安卓效率极高、成本极低但如果要兼容性测试、真机硬件能力验证它替代不了真机。2.4 云端远程真机设备这一类是我个人觉得现在最值得关注的平台把真机设备集中在云端用户通过远程ADB、远程投屏或API的方式使用。相当于你从买一台手机放工位上变成按小时租一台真机放在某个机房随时SSH过去用。QTPHONE就属于这个路线。区别在于它直接提供设备间的自动化接入逻辑你不用自己搭STF那套服务注册之后就能拿一台真实Android设备的连接信息然后在本地用ADB命令、Appium脚本、或你习惯的自动化框架去跑测试。设备本身是真实安卓机器不是容器镜像所以之前在模拟器上跑不动的反检测场景在云端真机上是正常的真机环境。表格看一下四种方案的取舍方案类型代表方式成本结构环境保真度适合场景主要局限自建设备墙STF 自购真机一次性硬件投入高维护人力多高对数据隐私要求极高的团队运维成本重扩展性差商业云真机大厂云测平台按次付费高兼容性测试、众测内网不友好持续集成成本不可控容器化安卓docker-android / Genymotion Cloud低按资源付费低大规模并行冒烟、UI回归仍是模拟器硬件能力失真云端远程真机QTPHONE这类设备云按时长/设备数付费高日常自动化、CI接入、远程调试网络依赖强设备需预约3. QTPHONE云端设备实测连接过程与第一印象先说清楚我这次实测QTPHONE目标不是做广告而是验证一条关键问题它能不能在真实工作流里替代我手头的真机和本地模拟器。我设了三个硬指标能不能用ADB正常控制设备、能不能跑通Appium脚本、跑完以后测试结果是否可复现。这三个指标过了才有资格进入选型范围。3.1 拿到云端真机的第一步ADB连接整个连接过程比我想象中简单。QTPHONE的平台上会分配一台具体的云端设备设备列表里能看到当前安卓系统版本、分辨率、剩余存储空间这些基本信息。平台提供了设备的ADB连接地址和端口本质上就是ADB over TCP/IP。我这边的操作流程是这样的adb connect 123.xxx.xxx.xxx:端口 adb devices执行完以后adb devices列表里就会出现这台云端设备。接下来本地所有的ADB命令都直接作用于它和操作一台通过USB连在工位上的手机没什么两样。这里有个细节值得注意云设备的地址和端口不是固定的每次分配或续约后可能会变化所以最好写一个简单的初始化脚本把连接逻辑固化下来避免每次手动复制粘贴。3.2 第一印象它不是模拟器是真机器连接上以后我先通过ADB查看了设备信息确认它到底是不是真机。关键看几个字段ro.product.model、ro.hardware、ro.board.platform以及传感器列表。实测结果和我办公桌上的真机基本一致能检测到真实的加速度传感器、陀螺仪、光线传感器摄像头也不是虚拟设备。CPU信息里的vendor_id、SOC型号都能和实际硬件对上。这一点对自动化测试非常关键。之前我拿本地模拟器跑某个地图类App定位SDK直接提示当前设备不支持高精度定位因为模拟器里的GPS是伪数据同样的用例切到QTPHONE云端设备上定位流程正常走通了。顺带把之前挂在本地模拟器上的扫码用例也跑了一遍取景框能正常启动图像识别流程完整。3.3 实际跑自动化测试的延迟表现远程设备最让人担心的就是延迟。ADB命令走网络会有额外RTTUI自动化的每一个操作都会有等待时间。我实际用Appium跑了一个简单的登录用例从启动App、输入账号密码、点击登录到断言主页元素出现整体耗时大概比本地USB真机多出30%左右。这个延迟是可以接受的——自动化测试本来就是非实时验证只要不是毫秒级时序判断影响不大。但如果你的用例里有大量滑动、拖拽、连续点击这类高频操作建议把Appium的waitForIdle超时和元素等待时间稍微放宽一点后面第四部分详细说。4. 从本地模拟器迁移到云端真机完整实操路径我想大多数读者和我情况类似已经有了在本地模拟器上写好的Appium/Python测试代码。迁移到云端真机核心工作是改连接配置而不是重写用例。下面是我走通的完整路径。4.1 环境准备本地环境为macOSPython 3.9Appium 2.0Appium-Python-Client。云真机环境为QTPHONE分配的一台Android 13设备分辨率1080x2400已开启开发者模式和USB调试。在跑脚本之前先通过ADB做三件基础操作解锁屏幕、关闭动画、保证WiFi连接。adb shell input keyevent 82 adb shell settings put global window_animation_scale 0 adb shell settings put global transition_animation_scale 0 adb shell settings put global animator_duration_scale 0关闭动画的原因是UI自动化在做元素查找和坐标点击时动画过程会干扰状态判断。这也是本地模拟器上常用的一套操作云端设备同样适用。4.2 Appium Desired Capabilities配置关键代码块如下from appium import webdriver desired_caps { platformName: Android, platformVersion: 13, deviceName: QTPHONE_Android13, udid: 云设备分配的UDID, noReset: True, unicodeKeyboard: True, resetKeyboard: True, automationName: UiAutomator2, newCommandTimeout: 300, } driver webdriver.Remote(http://127.0.0.1:4723/wd/hub, desired_caps)udid是这里最关键的字段它对应云端设备的标识。Appium通过这个标识决定把脚本跑在哪台设备上。如果你的Appium服务跑在本地云端设备只是通过ADB Remote连接到本机那这里的remote_url依然指向本地4723端口不需要指向云平台。4.3 从模拟器的测试对象切换到真机的适配点我实际迁移了一个日活较高的工具类App测试用例集共18条用例覆盖启动、登录、列表滑动、设置页切换、推送通知这几个模块。迁移过程中遇到三个和模拟器环境差异明显的点第一个是元素定位的等待时间。模拟器上我用3秒的隐式等待基本就够云端真机上需要调到5到8秒尤其是App冷启动阶段。原因是远程ADB链路的指令传输有额外延迟加之上传APK包和启动进程都要走网络。第二个是App安装方式。本地模拟器我常用adb install -r直接装APK云端设备也支持这个命令但包体大的时候超过200MB上传会比较慢。建议先确认设备上是否已有目标应用没有的话再安装节省重复上传时间。第三个是输入法干扰。模拟器上一般已经关闭了物理键盘或配置好了中文输入法云端真机是原生系统直接driver.send_keys()时偶尔会被系统输入法弹窗遮挡。我改用ADB方式注入文本绕开了这个问题def adb_input_text(text): text text.replace( , %s) os.system(fadb shell input text {text})4.4 在持续集成流水线上跑云端设备我额外测了一下在Jenkins流水线里调用云端设备执行测试。做法是在流水线脚本里先执行adb connect然后通过命令行方式启动Appium测试。由于QTPHONE提供的是标准ADB接口Jenkins slave只需要装有ADB和Python环境不需要额外插件接入成本很低。并发执行是这个环节最容易踩坑的地方。每一条流水线任务如果都申请独立设备需要注意云平台的并发设备数限额如果你的任务可以共享设备一定要在测试代码里做好应用状态清理防止不同任务的登录态互相干扰。我见过同事在这上面翻过车——两个并发任务跑同一个AppA任务把应用退出登录了B任务的用例断言当场失败排错排了一下午。5. 实测中踩过的坑和平台特性观察这一部分我挑了几个有代表性的问题都是本地真机上不太会遇到、但云端环境下非常典型的坑。5.1 云设备默认不是桌面待命状态第一坑就是设备可能是锁屏的。本地工位真机你可以手动点亮屏幕模拟器默认窗口就在屏幕上但云端设备在你不操作的时候是熄屏状态。如果脚本在连接后第一时间就去查找元素大概率直接超时。我的做法是在每次测试开始前都先执行一组唤醒屏保基础命令adb shell input keyevent KEYCODE_WAKEUP adb shell wm dismiss-keyguard adb shell input keyevent 82这组命令的意思分别是唤醒设备、忽略锁屏、模拟菜单键解锁。不加这三行后面的脚本可能连App都打不开。5.2 网络环境的改动会影响用例断言云设备所在机房的网络环境和你在本地办公室不一定完全一致。如果你在用例里硬编码了某些IP、域名或者依赖本地WiFi的环境配置那到云端设备上必然挂掉。比如我们有一个用例要连公司内网的某个测试服务云端设备访问不了就需要通过平台提供的网络配置能力做内网穿透或者在用例里先把数据Mock掉。我后来在代码里加了一个环境判断当检测到设备不在本地网段时自动切到Mock数据源这样同一套用例在本地模拟器和云端真机上都能跑。5.3 长连接的稳定性问题一次性跑30分钟以内的用例连接一般稳定。但如果你跑的是数小时的长稳测试偶尔会遇到ADB连接断开。原因是云端设备长时间空闲或网络策略导致TCP连接被回收。我的应对方式是在长稳脚本里加定期探活如果发现adb devices里设备变成offline状态就重新connect再接上adb disconnect adb connect 123.xxx.xxx.xxx:端口 adb wait-for-device然后恢复测试现场。这个处理要写在测试框架的兜底逻辑里而不是靠人盯着。5.4 远程设备的系统弹窗比模拟器更真实模拟器上的系统弹窗比如定位授权、通知权限、电池优化弹窗通常比较规矩触发一次处理一次。但真机在全新状态下首次启动App的权限弹窗是一串接着一串的。云端设备如果是全新设备跑第一个用例时会被各种权限请求打断。建议在测试脚本里预置权限授权逻辑。最简单的做法是切到权限管理页统一授权或者直接用ADB授予权限adb shell pm grant com.example.app android.permission.ACCESS_FINE_LOCATION adb shell pm grant com.example.app android.permission.CAMERA在云设备上初始化环境时做一次后面用例就顺畅很多。5.5 设备时区、语言设置默认值云平台分配的设备时区和语言可能不是你的业务默认值。比如设备语言是英文你用例里按中文文本定位元素就会找不到。所以初始化脚本里也要包含时区和语言设置我一般设置成中文、中国时区adb shell settings put system system_locales zh-CN adb shell service call alarm 3 i32 1设置完以后最好重启一下目标App确保语言资源重新加载。6. 什么场景适合云端真机什么场景别硬上实测下来我对云端真机方案有了比较清晰的认知。它适合的场景总结起来有三类。第一类是跨机型兼容性测试。你不需要每个机型都买一台真机放在家里吃灰需要用的时候从云平台申请一台对应机型跑完测试释放掉成本比自购低很多。尤其是针对一些冷门机型或老版本Android系统自己找一台都不容易云平台反而覆盖得全。第二类是持续集成流水线里执行回归测试。CI最需要的是环境稳定、可重复、可并发。云端设备通过ADB连接容易被自动化脚本控制平台侧也做了设备生命周期管理非常适合作为CI的测试资源池。第三类是分布式团队协同调试。之前遇到一个线上Bug开发在异地本地复现不出来。现在直接把云端设备地址抛给他他连上去就能复现、打日志、改代码再验证省了一趟快递寄手机的过程。但也有不能硬上的场景。第一如果你的App严重依赖本地WiFi局域网环境比如要连接同网段的智能硬件云设备是连不上的除非平台专门支持。第二对时延极其敏感的测试比如毫秒级的音频同步、视频播放卡顿分析远程链路引入的抖动会影响测量结果这类还是要在本地真机上做。第三如果项目有严格的数据合规要求所有测试数据必须留在内网那么你需要确认云平台是否能满足合规要求或者选择私有化部署方案直接用公网云设备可能不满足合规要求。我个人的建议是混合策略日常调试和用例开发继续用本地模拟器速度快、迭代方便CI回归和兼容性验证用云端真机补足覆盖面只有那些对硬件能力有极端要求的场景再专门保留一两台本地真机做深度验证。这样既有速度又有保真度成本也控制在合理范围。7. 最后补一句大实话我这次完整实测QTPHONE最大的感受不是某个平台怎么样而是安卓自动化测试的资源组织方式确实在发生变化。以前提到测试设备第一反应就是买手机、搭模拟器现在设备上云已经是一个可以认真考虑的选项标准ADB协议让迁移成本低到几乎可以忽略。你不需要改变现有的Appium脚本逻辑只是把设备来源从桌面上的一台手机换成了网络另一端的一台真实手机。如果你正在纠结测试环境方案我建议别急着买一堆真机也别死磕模拟器而是先把你手头的核心用例在云真机上跑一遍感受一下延迟和稳定性在你自己的场景下是否可接受。根据我的经验大多数UI自动化测试场景云端真机的表现已经足够胜任了。至于哪天延长时间、加重负载、上并发那是下一步再考虑的事。
返回列表