使用指南
自动化测试
Android 自动化实践

如何在 Android 设备上进行自动化测试

本文面向 在 PandaTest 上跑 Android 自动化 的场景:设备挂在 Agent 上、任务在测试容器里执行。你要解决的问题(连哪台机、脚本里怎么指设备、ADB 怎么用)是一回事。

1. 读完你能直接做的事

  • 确认 Android 真机已被 Agent 识别并出现在控制台
  • 构建套件 里选对设备,让任务跑到指定序列号上
  • 在 pytest / uiautomator2 / Appium / Airtest 脚本里 正确读取当前任务分配的设备
  • 理解 测试容器里 ADB 连的是宿主机,避免照抄本地 127.0.0.1 踩坑
  • 区分 多机并行(多任务)单脚本里切换多台设备

2. 和「本地 IDE 直连手机」差在哪里

维度本地 IDE(如插 USB 开 IDE)PandaTest
设备物理连接本机 USBAgent 机器 USB / 机房
ADB本机 adbAgent 宿主机 adb任务在 Docker 里通过转发连这台 adb
选哪台手机IDE 里点选构建套件里 指定设备过滤条件;平台下发 device_serial
一次运行多台自己开多进程/多线程套件 并发 + 多 Task,每台设备一个 Task,各跑一份脚本进程

平台侧会把每台任务机上的 device_id(ADB 序列号) 传给执行器;测试镜像启动时环境变量里会有 DEVICE_ID,脚本应以此为准,而不是写死序列号。

3. 前置:设备必须先被 Agent 识别

  1. Agent 所在机器已安装并运行 ADB,手机开启 USB 调试并已授权。
  2. 在宿主机执行 adb devices 能看到序列号(或 ip:port 形式的无线调试地址)。
  3. 控制台 设备中心 里该设备在线且可被占用。

详细接线步骤见 Android 设备接入;各品牌打开调试见 各品牌USB调试(侧栏可换品牌)。

⚠️

若设备在 Agent 上显示 unauthorized 或未出现在 adb devices 中,任务会在连接阶段失败;先解决宿主机 ADB,再跑自动化。

4. 在平台上跑起来:构建套件 → 任务

  1. 自动化测试 → 构建套件 中配置脚本来源(Git / 上传包)、被测 APK、目标设备(具体设备 ID 或 Android 过滤条件)。
  2. 选择与环境镜像匹配的 测试框架(如 pytest,以及镜像内已集成的 uiautomator2、Appium、Airtest 等)。
  3. 点击 运行:平台为每台选中设备创建一个 Task,并调度到对应 Agent 上的测试容器执行。

更细的字段说明见 套件配置与运行;结果与日志见 测试结果与定位

5. 脚本如何知道「当前是哪台手机」:环境变量

任务启动后,运行器会向进程注入(你可以在 任务详情 → 执行日志 里看到变量表):

变量含义
DEVICE_ID当前 Task 绑定的设备序列号(ADB serial),脚本里应优先读它
PLATFORMandroid
DEVICE_NAME控制台中的设备名称(展示用)
APP_PACKAGE套件里配置的应用包名(若有)
TASK_ID / JOB_ID任务与作业 ID,用于日志或上报
TEST_TIMEOUT超时秒数

构建套件里 环境变量 区块的键值也会合并进来(不要与上面重名覆盖关键变量,除非你清楚后果)。

测试容器内的 ADB 与 Python 库

执行 Android 任务时,镜像内会配置 ADB 指向 Agent 宿主机(例如通过 host.docker.internal:5037 转发),与你在本机直接插手机时「adb server 在本机」一致,只是 server 在宿主机、client 在容器

因此:

  • Shell 里可直接 adb -s "$DEVICE_ID" shell ...(前提是镜像入口脚本已就绪,平台提供的 runtest 流程会先等待设备在线)。
  • 不要在脚本里写死 127.0.0.1:5037 指宿主机;若某框架必须写 URI,应使用环境变量或文档推荐的宿主机别名(与镜像内 ADB_SERVER_SOCKET / ANDROID_ADB_SERVER_HOST 一致)。

6. 在代码里连接设备

uiautomator2

import os
import uiautomator2 as u2
 
serial = os.environ["DEVICE_ID"]
d = u2.connect(serial)

Appium(示例思路)

在 Desired Capabilities 里把 udid(或等价字段)设为 os.environ["DEVICE_ID"]app 若已由平台安装,可按你们项目约定只启动包名。

Airtest

容器内已注入与 ADB 相关的环境变量。连接字符串需指向 当前 ADB 可访问的那台 server,且 serial 为 DEVICE_ID,例如:

import os
 
device_id = os.environ["DEVICE_ID"]
host = os.environ.get("DEVICE_HOST", "host.docker.internal")
port = os.environ.get("DEVICE_PORT", "5037")
# 按你使用的 Airtest 版本调整 URI 格式
uri = f"android://{host}:{port}/{device_id}"
from airtest.core.api import connect_device
connect_device(uri)

若使用 Android:/// 且仅一台设备已连接在当前 ADB 视图下,部分场景也可工作,但 多机并行时务必显式带 serial,避免连错机。

直接执行 ADB

import os
import subprocess
 
serial = os.environ["DEVICE_ID"]
subprocess.run(["adb", "-s", serial, "shell", "getprop", "ro.product.model"], check=True)

平台镜像也支持在 shell 脚本中用 adb -s "$DEVICE_ID"

7. 多机:并行 vs 单脚本多设备

  • 并行跑多套用例:在构建套件里选多台设备、打开并发;平台会为 每台设备起一个独立 Task,各自进程里只有一个 DEVICE_ID。这是最常见、最稳的方式。
  • 同一脚本逻辑要操作两台手机(例如互加好友):默认 一个 Task 只绑定一台设备;多机协作通常用 多个 Task 并行、拆分脚本,或在符合网络与安全策略的前提下在脚本内自行 adb connect 第二台。不要假设「连上多台就会自动在所有设备上各跑一遍」。

8. 本地写脚本、云端跑:控件获取

在控制台用 控件获取 连上设备,边查 UI 树边写 Python(如 uiautomator2),再提交到 Git 或由套件拉取。见 控件获取

9. 自查清单

  1. Agent 上 adb devices 是否正常、序列号是否与控制台一致?
  2. 构建套件里设备筛选是否过宽,导致 Task 跑到了非预期机型?
  3. 脚本是否写死了序列号或 127.0.0.1,而不是读 DEVICE_ID
  4. 失败时看 任务详情 → 执行日志 里设备连接阶段是否已报错(超时、offline、未授权)?

下一步:按项目选 脚手架与模板 或自建 runtest.sh / pytest 入口,并把上述环境变量接进你们的 driver 初始化代码。