AI-移动端自动化框架构建 — 详细步骤与注意事项
📋 总体路线图
1Phase 1: 环境准备与技术选型(1天)
2 ↓
3Phase 2: 项目骨架搭建(0.5天)
4 ↓
5Phase 3: 核心框架开发(3天)
6 ├─ 3.1 驱动管理层
7 ├─ 3.2 Page Object基类
8 ├─ 3.3 工具层(日志/截图/ADB)
9 └─ 3.4 配置管理
10 ↓
11Phase 4: 用例开发实践(2天)
12 ↓
13Phase 5: CI/CD集成(1天)
14 ↓
15Phase 6: 优化与演进(持续)
16
🚀 Phase 1: 环境准备与技术选型
1.1 技术栈选型对比
| 维度 | 方案A(推荐) | 方案B | 方案C |
|---|---|---|---|
| 语言 | Python 3.10+ | Java | Kotlin |
| 核心框架 | Appium 2.x + pytest | Appium + TestNG | Espresso + XCTest |
| 页面模式 | Page Object + Screenplay | POM | MVP |
| 断言 | pytest + Allure | AssertJ + ExtentReport | 原生断言 |
| 设备管理 | ADB + uiautomator2 | Selenium Grid | Firebase Test Lab |
| 适合场景 | 跨平台、团队协作 | 大型企业、Java团队 | 原生性能测试 |
💡 推荐方案A的理由:
- Python上手快,测试人员友好
- pytest生态强大(参数化、插件、并行)
- Appium 2.x原生支持多设备
- Allure报告美观,CI集成简单
1.2 环境安装(详细步骤)
bash
1# ============ 1. 系统依赖 ============
2# macOS
3brew install node appium python@3.10
4
5# Ubuntu/Debian
6sudo apt-get install -y openjdk-11-jdk python3.10 python3-pip nodejs npm
7sudo npm install -g appium@2
8
9# Windows
10# 下载并安装:Java JDK 11、Python 3.10、Node.js
11# 然后:npm install -g appium@2
12
13# ============ 2. Appium服务端 ============
14appium driver install uiautomator2 # Android
15appium driver install xcuitest # iOS(仅macOS)
16
17# 验证安装
18appium --version # 应输出 2.x.x
19appium driver list # 查看已安装驱动
20
21# ============ 3. Android环境 ============
22# 安装Android SDK + Platform Tools
23sdkmanager "platform-tools" "platforms;android-34" "build-tools;34.0.0"
24
25# 验证ADB
26adb devices # 应看到设备列表
27
28# ============ 4. iOS环境(仅macOS) ============
29# Xcode 15+(包含iOS模拟器)
30xcode-select --install
31
32# 验证
33xcrun simctl list devices # 查看模拟器
34
35# ============ 5. Python依赖 ============
36pip install -U pip
37pip install appium==2.11.1 pytest==8.0.0 pytest-xdist==3.5.0
38pip install allure-pytest==2.13.3
39pip install pyyaml==6.0.1 python-dotenv==1.0.0
40pip install faker==24.2.0 # 测试数据生成
41pip install Pillow==10.2.0 # 图片处理
42
43# ============ 6. 验证环境 ============
44# 启动Appium服务
45appium --allow-insecure chromedriver_autodownload
46
47# 测试连接Android设备
48adb devices | grep -v "List" | wc -l # 应 > 0
49
50# 测试连接iOS模拟器
51xcrun simctl list | grep Booted
52
⚠️ 注意事项:
| 问题 | 原因 | 解决方案 |
|---|---|---|
appium命令找不到 |
npm全局路径未加入PATH | export PATH=$PATH:$(npm bin -g) |
| ADB连接失败 | 开发者模式未开/USB调试未开 | 手机设置→开发者选项→USB调试 |
| iOS WDA启动失败 | Xcode版本不匹配 | 更新Xcode或降级Appium |
| uiautomator2安装失败 | 网络问题 | 使用--registry=https://registry.npmmirror.com |
| Appium 2.x报错 | 旧版残留 | appium driver uninstall uiautomator2重装 |
📁 Phase 2: 项目骨架搭建
2.1 目录结构设计
bash
1mobile-automation/
2├── 📄 README.md # 项目说明(必写)
3├── 📄 requirements.txt # 依赖
4├── 📄 pyproject.toml # 项目配置(替代setup.py)
5├── 📄 pytest.ini # pytest配置
6├── 📄 .env.example # 环境变量模板
7├── 📄 .gitignore # Git忽略
8├── 📁 config/ # 配置文件
9│ ├── 📄 __init__.py
10│ ├── 📄 capabilities.yaml # 设备能力配置
11│ ├── 📄 locators.yaml # 元素定位
12│ └── 📄 test_data.yaml # 测试数据
13├── 📁 framework/ # 框架核心(不依赖业务)
14│ ├── 📄 __init__.py
15│ ├── 📄 base_page.py # Page Object基类
16│ ├── 📄 driver_manager.py # 驱动管理
17│ ├── 📄 config_loader.py # 配置加载
18│ ├── 📄 logger.py # 日志工具
19│ └── 📄 exceptions.py # 自定义异常
20├── 📁 pages/ # 页面对象(按业务模块)
21│ ├── 📄 __init__.py
22│ ├── 📄 base_page.py # 页面基类(业务相关)
23│ ├── 📄 login_page.py
24│ ├── 📄 home_page.py
25│ └── 📄 mine_page.py
26├── 📁 tests/ # 测试用例
27│ ├── 📄 __init__.py
28│ ├── 📄 conftest.py # pytest fixtures
29│ ├── 📁 smoke/ # 冒烟测试
30│ │ └── 📄 test_smoke.py
31│ ├── 📁 login/ # 登录模块
32│ │ └── 📄 test_login.py
33│ └── 📁 order/ # 下单模块
34│ └── 📄 test_order_flow.py
35├── 📁 utils/ # 工具函数
36│ ├── 📄 __init__.py
37│ ├── 📄 adb_helper.py # ADB封装
38│ ├── 📄 screenshot.py # 截图/录屏
39│ ├── 📄 api_helper.py # 接口请求
40│ └── 📄 data_factory.py # 数据工厂
41├── 📁 reports/ # 测试报告(.gitignore)
42│ ├── 📁 screenshots/
43│ ├── 📁 logs/
44│ └── 📁 allure-results/
45├── 📁 logs/ # 运行日志(.gitignore)
46├── 📁 .github/ # GitHub配置
47│ └── 📄 workflows/
48│ └── 📄 mobile_test.yml # CI配置
49└── 📁 docs/ # 文档
50 ├── 📄 framework_design.md
51 └── 📄 api.md
52
2.2 核心配置文件
📄 pyproject.toml
toml
1[tool.pytest.ini_options]
2testpaths = ["tests"]
3python_files = ["test_*.py"]
4python_classes = ["Test*"]
5python_functions = ["test_*"]
6addopts = """
7 -v
8 --strict-markers
9 --alluredir=reports/allure-results
10 --html=reports/report.html
11 --self-contained-html
12"""
13markers = [
14 "smoke: 冒烟测试用例",
15 "regression: 回归测试用例",
16 "flaky: 不稳定用例(需重试)",
17 "android: 仅Android",
18 "ios: 仅iOS",
19]
20
21[tool.coverage.run]
22source = ["framework", "pages"]
23omit = ["tests/*", "utils/adb_helper.py"]
24
25[tool.black]
26line-length = 100
27target-version = ["py310"]
28
📄 config/capabilities.yaml
yaml
1default:
2 platformName: Android
3 automationName: UiAutomator2
4 autoGrantPermissions: true
5 noReset: true # 保留App数据(调试用)
6 fullReset: false
7
8android:
9 deviceName: emulator-5554
10 platformVersion: "13"
11 appPackage: com.example.app
12 appActivity: .MainActivity
13 udid: emulator-5554
14
15ios:
16 deviceName: iPhone 15
17 platformVersion: "17.2"
18 app: /path/to/app.app
19 udid: A1B2C3D4-E5F6-7890-ABCD-EF1234567890
20 wdaLocalPort: 8100
21
22# 多设备配置(并行执行用)
23devices:
24 - name: Pixel6_Android13
25 udid: emulator-5554
26 platform: Android
27 port: 4723
28 - name: Pixel8_Android14
29 udid: emulator-5556
30 platform: Android
31 port: 4725
32 - name: iPhone15_iOS17
33 udid: A1B2C3D4
34 platform: iOS
35 port: 8100
36
📄 config/locators.yaml(元素定位)
yaml
1# 登录页
2login:
3 phone_input:
4 android: id=com.example.app:id/et_phone
5 ios: predicate="type == 'XCUIElementTypeTextField' AND placeholderValue == '请输入手机号'"
6 send_code_btn:
7 android: id=com.example.app:id/btn_send
8 ios: accessibility_id=发送验证码
9 code_input:
10 android: id=com.example.app:id/et_verify_code
11 ios: predicate="type == 'XCUIElementTypeSecureTextField'"
12 login_btn:
13 android: text=登录
14 ios: label=登录
15
16# 首页
17home:
18 search_bar:
19 android: id=com.example.app:id/et_search
20 ios: predicate="type == 'XCUIElementTypeTextField'"
21 tab_mine:
22 android: id=com.example.app:id/tab_mine
23 ios: accessibility_id=我的
24
25# 通用定位策略(降级方案)
26fallback:
27 - by: id
28 - by: accessibility_id
29 - by: xpath
30 - by: class_name
31
⚠️ 注意事项:
| 配置项 | 常见错误 | 正确做法 |
|---|---|---|
noReset: true |
缓存导致测试不干净 | 冒烟测试用true,回归用false |
appPackage |
包名写错 | 用adb shell pm list packages确认 |
wdaLocalPort |
iOS端口冲突 | 每个模拟器用不同端口(8100, 8101...) |
locators.yaml |
硬编码不利于维护 | 用YAML分层管理,支持环境覆盖 |
pytest.ini |
marker写错 | marker名称统一小写,用前先定义 |
🔧 Phase 3: 核心框架开发
3.1 驱动管理层(最高优先级)
📄 framework/driver_manager.py
python
1"""
2Appium驱动管理器
3- 单例模式,全局唯一
4- 支持多设备并行
5- 自动生命周期管理(启动/退出)
6- 失败自动重连
7"""
8import time
9import logging
10from typing import Optional, Dict, Any
11from appium import webdriver
12from appium.options.android import UiAutomator2Options
13from appium.options.ios import XCUITestOptions
14from selenium.common.exceptions import WebDriverException
15
16logger = logging.getLogger(__name__)
17
18
19class DriverManager:
20 """Appium驱动单例管理器"""
21
22 _instance: Optional['DriverManager'] = None
23 _drivers: Dict[str, webdriver.Remote] = {} # udid -> driver
24
25 def __new__(cls):
26 if cls._instance is None:
27 cls._instance = super().__new__(cls)
28 return cls._instance
29
30 def __init__(self):
31 if not hasattr(self, '_initialized'):
32 self._initialized = True
33 self.config = self._load_config()
34
35 def _load_config(self) -> dict:
36 """加载配置"""
37 import yaml
38 with open('config/capabilities.yaml',