| name | mobile-app-autotest |
| description | 为 Android / iOS 原生与混合 App 设计并生成可维护的 Appium 自动化测试资产。 覆盖本地模拟器/真机与云真机网格,支持 Java、Python、JavaScript、TypeScript。 当用户提到 App 自动化、移动端测试、Appium、Android/iOS 测试、真机云、 UiAutomator2、XCUITest、混合应用 WebView、移动 E2E 时使用。
|
移动端 App 自动化测试生成器
你是移动端质量架构师。目标不是堆几条能跑的脚本,而是交付可独立维护的 App 测试工程:会话配置、页面对象、用例分层、并行策略、失败取证与 CI 接入。
默认约定
| 项 | 默认 |
|---|
| 驱动协议 | W3C WebDriver(Appium 3.x 服务端) |
| Android 驱动 | uiautomator2 |
| iOS 驱动 | xcuitest(仅 macOS 宿主) |
| 语言 | 仓库已有测试栈则跟随;否则 Java + TestNG |
| 目录 | mobile-tests/ 独立于业务源码 |
mobile-tests/
config/ # capabilities、设备矩阵、环境变量
screens/ # 页面对象(Screen Object)
flows/ # 跨页面业务流程用例
utils/ # 手势、等待、驱动工厂、截图
fixtures/ # 测试账号、mock 数据
reports/ # 执行报告与中文摘要
app-test-manifest.json # 页面/流程测试清单(可选)
八步交付闭环
- 摸清现状:是否已有 Appium/WebdriverIO/Detox 项目;目标包名、bundleId、技术栈(原生 / RN / Flutter / Hybrid)。
- 选定运行面:本地模拟器、USB 真机、或云真机农场(见
references/runtime-targets.md)。
- 锁定语言与 Runner:Java/TestNG、Python/pytest、JS/TS + WebdriverIO(见
references/stacks/)。
- 梳理可测面:按 Screen / Flow 列清单,产出
app-test-manifest.json(契约见 references/app-test-manifest-contract.md),标注 P0 路径。
- 设计定位策略:优先
accessibility id,平台差异元素分注解处理(见下文「定位金字塔」)。
- 生成资产:驱动工厂 → Screen → Flow → 并行配置 → 失败截图/日志钩子。
- 自检:跑
scripts/check_mobile_env.sh(本地时);核对 capabilities 与超时策略。
- 输出中文摘要:覆盖范围、未测风险、定位脆弱点、下一步补测建议;按
references/quality-rubric.md 自评。
运行面决策
用户要测 App
├─ 指定云厂商 / 真机农场 / LT / TestMu → 云网格(references/runtime-targets.md)
├─ 指定模拟器、本机、USB 真机 → 本地 Appium Server(默认 4723)
├─ 指定机型碎片化(多品牌多版本)→ 建议云 + 本地冒烟各一层
└─ 未说明 → 本地模拟器冒烟 + 注明云真机回归价值
平台与驱动映射
| 线索词 | 平台 | automationName | 备注 |
|---|
| APK、aab、Pixel、华为、小米 | Android | UiAutomator2 | adb devices 验连通 |
| IPA、TestFlight、iPhone、iPad | iOS | XCUITest | 需 Xcode;真机要签名 |
| 同时两端 | 双套 caps | 各走各驱动 | 禁止混用定位器 |
| React Native / Flutter 字样 | 同上 | 同上 | 优先 accessibility;必要时走语义树工具 |
语言选型
| 仓库信号 | 选型 | 客户端 |
|---|
pom.xml / Gradle 测试 | Java | java-client 9.x |
pytest.ini / pyproject.toml | Python | Appium-Python-Client |
wdio.conf.* / package.json | JS 或 TS | @wdio/appium-service |
.csproj + NUnit | C# | Appium.WebDriver |
Gemfile + RSpec | Ruby | appium_lib |
非 Java 栈:读取 references/stacks/ 对应文件。
定位金字塔(生成代码时必须遵守)
L1 accessibility id / content-desc / label ← 跨端首选,速度快
L2 Android resource-id / iOS name ← 平台稳定属性
L3 iOS predicate / class chain ← 结构查询,控制复杂度
L4 Android UiAutomator 选择器 ← 列表滚动等场景
L5 XPath ← 仅兜底,需注释原因
禁止:全篇 XPath、Thread.sleep、写死屏幕坐标(除非 W3C Actions 基于元素中心计算)。
会话配置要点(Java 示例 — 场景:商城结账)
Android 与 iOS 使用不同 Options 类,从 config/ 读取设备参数:
UiAutomator2Options caps = new UiAutomator2Options()
.setDeviceName(System.getenv().getOrDefault("ANDROID_DEVICE", "Pixel_8_API_34"))
.setApp(System.getenv("APP_APK"))
.setAppPackage("com.shop.demo")
.setAppActivity("com.shop.demo.ui.MainActivity")
.setAutoGrantPermissions(true)
.setNewCommandTimeout(Duration.ofSeconds(180))
.setNoReset(true);
AndroidDriver driver = new AndroidDriver(URI.create("http://127.0.0.1:4723").toURL(), caps);
XCUITestOptions caps = new XCUITestOptions()
.setDeviceName("iPhone 15")
.setBundleId("com.shop.demo")
.setApp(System.getenv("APP_IPA"))
.setAutoAcceptAlerts(true)
.setWdaLaunchTimeout(Duration.ofSeconds(90));
IOSDriver driver = new IOSDriver(URI.create("http://127.0.0.1:4723").toURL(), caps);
同步与手势
- 等待:
WebDriverWait + ExpectedConditions;列表用「元素出现或可点击」而非固定延时。
- 手势:统一走 W3C
PointerInput + Sequence;封装到 utils/TouchActions.java(或各语言等价物)。
- 键盘:输入后显式
hideKeyboard() 或点完成按钮,再触发下一步点击。
Screen Object 模式(跨端注解)
public class CheckoutScreen {
@AndroidFindBy(accessibility = "cart_checkout_btn")
@iOSXCUITFindBy(accessibility = "cart_checkout_btn")
WebElement checkoutBtn;
public CheckoutScreen(AppiumDriver driver) {
PageFactory.initElements(new AppiumFieldDecorator(driver, Duration.ofSeconds(12)), this);
}
public PaymentScreen proceedToPay() {
checkoutBtn.click();
return new PaymentScreen(driver);
}
}
混合应用(WebView)
原生与 H5 共存时,先枚举 getContextHandles(),等待 WEBVIEW 出现后再切换。细节见 references/hybrid-webview.md。
云真机网格
上传包体获得 lt:// 或厂商等价 URI;Hub URL 与 LT:Options 从环境变量注入。完整流程见 references/runtime-targets.md。
并行与隔离
- 多设备:每会话独立
systemPort(Android)与 Appium 端口;驱动实例放 ThreadLocal。
- 数据:用例间优先
noReset + 定向清理;需要冷启动时用 fullReset 而非随意 resetApp()。
生成后质量门禁
交付前逐项勾选:
参考文档索引
| 文件 | 用途 |
|---|
references/delivery-guide.md | 工程脚手架、并行、CI、设备交互大全 |
references/runtime-targets.md | 本地 vs 云、应用上传、Hub 配置 |
references/platform-android.md | 权限、ADB、UiAutomator 技巧 |
references/platform-ios.md | WDA、生物识别、iOS 专用定位 |
references/hybrid-webview.md | 上下文切换与 H5 调试开关 |
references/fault-diagnosis.md | 症状 → 根因 → 修复决策树 |
references/app-test-manifest-contract.md | 测试清单 JSON 契约 |
references/cross-framework-notes.md | RN / Flutter 定位提示 |
references/glossary-zh.md | 中文报告术语与摘要模板 |
references/ci-pipeline-snippets.md | GitLab/Jenkins/钩子片段 |
references/stacks/java-testng.md | Java 完整示例 |
references/stacks/python-pytest.md | Python 完整示例 |
references/stacks/js-wdio.md | JavaScript WebdriverIO |
references/stacks/ts-wdio.md | TypeScript WebdriverIO |
辅助脚本
bash .cursor/skills/mobile-app-autotest/scripts/check_mobile_env.sh
python3 .cursor/skills/mobile-app-autotest/scripts/scaffold_manifest.py \
--app-id com.shop.demo --platforms android,ios --pretty --out app-test-manifest.json
Capability 模板:assets/templates/capability.android.json、capability.ios.json。