测试环境搭建:多版本模拟器、云真机、本地物理设备管理

要说回归测试最头疼的事,环境搭建肯定排前三。你想想看,一个App要兼容Android 10到14,光设备就得好几台。我不止一次见过团队因为环境不全,漏测了某个版本的兼容性bug,发版后被用户骂惨。今天我来聊聊我这些年积累下来的设备管理经验——怎么把模拟器、云真机和本地物理设备搭成一个高效、可复用的“测试舰队”。

测试环境搭建体系 覆盖 Android 10 ~ 14,三套环境互相补充 多版本模拟器 · 命令行 / SDK Manager 创建 · 快照加速,数据盘分离 · Google Play 模拟器做 GMS 测试 云真机平台 · 远程真机 / 多机型并行 · 兼容性矩阵 + 自动化轮询 · 厂商定制 ROM 覆盖 本地物理设备 · USB / WiFi ADB 连接 · 设备池 + 标签化管理 · 刷机 / 降级 / 定制系统工具 测试执行:根据版本 & 机型需求,动态分配环境 CI 流水线自动选取,人工复查重点用例

多版本模拟器——快速迭代的法宝

模拟器是我个人用得最多的环境。不是因为它最准,而是因为“快”——一秒起一个,想跑几版本就几个版本。我习惯用命令行创建,而不是GUI点点点,为啥?因为要批量。

举个例子,一个回归测试需要覆盖 API 29 到 34,你可以这样批量创建:

# 列出可用系统镜像
avdmanager list target

# 创建 AVD(指定API级别、ABI、设备ID)
for api in 29 30 31 32 33 34; do
  echo no | avdmanager create avd \
    -n "test_$api" \
    -k "system-images;android-$api;google_apis;x86_64" \
    -d "pixel_6"
done
小技巧: 创建完模拟器别忘了设置 -memory 1536 和 -partition-size 2048。我遇到过默认512M内存,App一跑就OOM。另外,开了快照(Quick Boot)后,启动时间能从30秒降到5秒。

说到模拟器的“快照”功能,我真的离不开。每次回归测试前,我会把模拟器恢复到“纯净系统”快照,然后安装测试包。这样做能保证每次环境一致,不会被上个测试残留污染。命令也很简单:

# 保存快照
adb emu avd snapshot save clean_state

# 恢复快照
adb emu avd snapshot load clean_state

还有一类特殊的模拟器——带Google Play服务的版本。如果你的App依赖GMS(Google Mobile Services),比如地图、推送,那你必须用 google_apis_playstore 镜像。我曾经因为用了不带Play Store的镜像,测试一直报“Google Play服务缺失”,浪费了半天才反应过来。

云真机平台——弥补真实设备缺口

模拟器再快,也模拟不出真实设备的传感器、厂商定制和网络抖动。这时候云真机就派上用场了。说白了,云真机就是帮你租用真实设备,远程操作。

我个人用云真机主要干三件事:

  • 兼容性矩阵测试:一次性跑几十台不同品牌、型号、系统的机器,看看有没有闪退、UI错位。
  • 定向复现:用户反馈某个bug只在某款手机上出现,我就去云真机找到同款,抓日志复现。
  • 自动化并行:CI里面触发回归,同时分配5~10台云设备执行用例,半小时搞定原来一天的工作。
注意: 云真机的网络环境是远程的,所以依赖外部网络或者蓝牙的测试要小心。我遇到过在云真机上跑通,但用户本地wifi环境下挂了——因为云真机的WiFi延迟很低,和真实场景不同。建议云真机只做功能验证,性能/网络相关测试还是要回本地物理设备。

云真机平台通常会提供API来管理设备和执行测试。常见的操作有:

# 假设使用某个平台API(示例伪代码)
# 获取可用设备列表
GET /v1/devices?status=idle&osVersion=13

# 分配设备
POST /v1/jobs
{
  "deviceId": "samsung_s23_android13",
  "package": "com.example.app",
  "testRunner": "androidx.test.runner.AndroidJUnitRunner"
}

# 同步等待结果
GET /v1/jobs/{jobId}/report

用云真机的时候,我还建议你在设备选择上做一个“最小覆盖矩阵”。比如你的App目标用户中,vivo和小米各占30%,那就优先在这两个品牌上跑;其他品牌轮着测即可。不要每次把所有型号都跑一遍,成本太高。

本地物理设备管理——最后的防线

我最信任的还是本地物理设备。为什么?因为你能摸到、能插USB线、能直接刷机。尤其是一些模拟器搞不定的场景:比如刘海屏、系统字体缩放、第三输入法、低电量弹窗等。我在项目中有个“铁三角”:一台Pixel 6(跑最新Android 14)、一台小米12(跑Android 13,国内定制)、一台OPPO Find X5(跑Android 12,测试小屏适配)。

管理多台物理设备,核心痛点有两个:

  1. 连接管理:几台设备USB都插在主机上,adb devices会列出好几个,容易搞混。我的办法是用 adb -s 设备序列号 指定操作,结合设备标签。
  2. 状态一致性:每台设备必须恢复到同一“基线”状态——比如统一关闭自动更新、关闭动画、安装好Root证书。我写了个初始化脚本:
# 批量初始化设备
for device in $(adb devices | grep device$ | awk '{print $1}'); do
  adb -s "$device" shell settings put global animator_duration_scale 0
  adb -s "$device" shell settings put global window_animation_scale 0
  adb -s "$device" shell settings put global transition_animation_scale 0
  adb -s "$device" shell settings put global wifi_scan_always_available 0
  adb -s "$device" shell settings put global auto_time 0
  adb -s "$device" install -r -g your_certificate.apk
done

另外,如果你有多台设备,建议用 设备池 管理。我写了一个简单的标签系统,给每台设备打上标签:android13|xiaomi|smoke,然后用脚本根据测试需求自动选取。

核心原则: 本地物理设备用来跑“高危”用例(如支付、相机、定位、多语言)。模拟器跑普通功能。云真机补全碎片化覆盖。三者结合,既快又准。

一个常见的问题是:怎么让物理设备长期稳定地挂着?我推荐使用USB Hub供电,不要通过电脑的USB口供电(电流不够)。另外,WiFi ADB也是个好选择,避免线缆松动导致断开——

# 开启WiFi ADB(需在同一局域网)
adb tcpip 5555
adb connect 192.168.1.100:5555

这样设备放桌上,不用插线也能跑测试。

环境统一管理——少走弯路的经验

最后聊聊环境之间的协同。我见过很多团队,模拟器、云真机、本地设备各管各的,测试用例也分开维护,浪费人力。我的建议很简单:

  • 建一个设备列表配置文件(YAML/JSON),标注每个设备的OS版本、品牌、可用状态、测试标签。
  • 回归启动时,CI脚本读取配置,自动分配用例到对应的环境。
  • 保留一个人工干预的接口:比如某个失败用例需要手动重跑,能快速指定到某台设备。

我自己常用的设备表结构:

devices:
  - id: "emulator_android10"
    type: emulator
    api: 29
    abi: x86_64
    google_play: true
    tags: ["smoke", "functional"]

  - id: "cloud_samsung_a52"
    type: cloud
    model: "SM-A525F"
    api: 31
    provider: "test_lab"
    tags: ["medium", "camera"]

  - id: "local_pixel6"
    type: physical
    serial: "XXXXXXX"
    api: 34
    cable: usb
    tags: ["critical", "performance"]

这样做的好处是,你只要改配置文件,测试流程就自动适配。比如新买了一台设备,加一行就能干活,不用改代码。

避坑指南: 我曾经把模拟器和物理设备的快照混用,结果模拟器的快照恢复到物理设备上,导致一些系统库版本不匹配。每个环境的数据要独立保存,别偷懒。

好了,以上就是这些年我折腾设备管理的一点心得。环境搭建看似繁琐,但一旦变成自动化流程,后续的回归测试就能省下大量时间。你要是刚开始做多版本回归,先别贪多,从模拟器和两台本地设备起步,慢慢把云真机加进来。稳扎稳打,比你一步到位要靠谱得多。