本UI自动化测试框架采用Page Object设计模式,结合Airtest图像识别和Poco
UI自动化技术,实现稳定可靠的自动化测试。
🛠️ 技术栈:
- Airtest- 跨平台UI自动化测试框架(图像识别)
- Poco- UI自动化引擎(控件识别)
- Pytest- Python测试框架
- Allure- 测试报告生成工具
- Python 3.12+- 编程语言
Airtest框架官方文档:https://airtest.doc.io.netease.com/tutorial/0_automated_testing/
一、环境安装
1、安装本地airtest Python环境
pip install pytest pip install airtest==1.4.3 pip install --no-compile pocoui==1.0.94 pip install allure-pytest==2.16.0同时安装Airtest IDE软件,方便元素定位与图片截取
2、安装Allure Commandline
目的:把 allure-pytest 收集到的测试结果,渲染成可视化的 HTML 测试报告,并支持本地预览、CI 归档和分享
Windows (使用Scoop):
# 先安装 Scoop(如果尚未安装) Set-ExecutionPolicy RemoteSigned -Scope CurrentUser irm get.scoop.sh | iex scoop install allure二、搭建测试框架
这里以一个核心功能为快速扫描病毒的安卓TV应用项目为例,来搭建UI自动化测试框架
1、框架结构
UI/ ├── config/ # 配置模块 │ ├── app_config.py # 应用配置(包名、超时时间等) │ └── device_config.py # 设备配置 ├── actions/ # 基础操作层 │ ├── base_action.py # Page基类(通用操作方法) │ └── tv_remote.py # TV遥控器操作封装 ├── pages/ # 页面对象层 │ ├── home_page.py # 首页页面对象 │ └── problem_area_page.py # 问题区域页面对象 ├── testcases/ # 测试用例层 │ └── test_quick_scan.py # 快速扫描测试用例 ├── utils/ # 工具类模块 │ ├── assert_utils.py # 断言工具(集成Allure截图) │ ├── device_utils.py # 设备连接工具 │ ├── poco_elements.py # Poco元素定位器常量 │ └── poco_manager.py # Poco单例管理器 ├── resources/images/ # 图片资源(截图模板) ├── screenshots/failures/ # 断言失败截图 ├── reports/ # 测试报告目录(Git忽略) ├── conftest.py # Pytest配置文件(Fixture定义) ├── pytest.ini # Pytest配置 ├── run.py # 测试运行脚本 └── view_report.py # 报告查看脚本2、 核心特性
1. Page Object模式
- pages/- 封装页面元素和操作
- actions/base_action.py- 提供通用操作方法
- 提高代码复用性和可维护性
2. Poco单例管理
- utils/poco_manager.py- 单例模式管理Poco实例
- 避免重复创建,提高性能
- 自动处理设备重连
3. 智能断言
- utils/assert_utils.py- 统一断言入口
- 支持Poco文本断言和图片断言
- 失败自动截图
4. TV遥控器封装
- actions/tv_remote.py- Android TV遥控器操作
- 支持方向键、确认键、返回键等
- 提供便捷的导航方法
- 可与Poco混合使用
5. Allure报告集成
- 详细的测试步骤展示
- 测试分类和严重程度标记
- 美观的HTML报告界面
3、 常用命令
# 安装依赖pipinstall-rrequirements.txt# 运行所有测试python run.py# 运行指定测试文件pytest testcases/test_quick_scan.py-v# 运行带标记的测试pytest-msmoke# 冒烟测试pytest-mcritical# 关键测试# 生成Allure报告allure generate reports/allure_results-oreports/allure_report--clean# 查看报告allureopenreports/allure_report# 清理缓存pytest --cache-clear4、测试报告
Allure报告包含:
- ✅ 测试执行概览
- ✅ 测试步骤详情
- ✅ 失败用例分析
- ✅ 测试趋势图表
- ✅ 环境信息
三、测试用例实例
1、两套核心断言技术:Airtest vs Poco
这是整个框架最关键的区分。理解了它们的差异,就知道什么场景用什么。
| 维度 | Airtest(图像识别) | Poco(UI 控件树) |
|---|---|---|
| 原理 | OpenCV 模板匹配,在屏幕截图中找图 | 读取 Android UI 层级树,按属性定位元素 |
| 定位方式 | 图片模板Template(img) | text / resourceId / textMatches |
| 稳定性 | 受分辨率、主题、动画影响 | 只要控件属性不变就稳定 |
| 速度 | 慢(需截屏+模板匹配) | 快(直接查控件树) |
| 能断言什么 | 图片是否存在(图标、logo) | 文本、按钮、列表项等有属性的控件 |
统一断言入口assert_element,封装三种断言方法
poco_selector(最推荐) > text > img(兜底)
defassert_element(img=None,text=None,poco_selector=None,timeout=10,interval=1,msg="元素不存在",snapshot_on_fail=True,test_name=None):"""统一断言入口"""_log(f"开始断言: text={text}, img={img}, selector={poco_selector}")# 优先使用Poco断言iftextorpoco_selector:poco=PocoManager.get_instance()start=time.time()whiletime.time()-start<=timeout:try:iftextandpoco(text=text).exists():_log("Poco断言成功")returnTrue# poco_selector 为字典选择器(如 {"text": "xx", "name": "yy"}),# 必须用 ** 解包为关键字参数;整体作为位置参数传入会抛异常并被下方 except 静默吞掉ifpoco_selectorandpoco(**poco_selector).exists():_log("Poco断言成功")returnTrueexceptException:passtime.sleep(interval)_log("Poco未命中")# fallback到图片断言ifimg:try:# 等待图片出现pos=wait(Template(img),timeout=timeout)ifpos:_log("图片断言成功")returnposexceptException:_log("图片断言未命中")# 失败处理ifsnapshot_on_fail:file=_screenshot("assert_fail",test_name)_log(f"截图:{file}")raiseAssertionError(f"{msg}| text={text}| img={img}")2、三种用法及适用场景
① Poco 选择器断言(poco_selector)— 最推荐
适用于:动态文本、需要多条件组合定位的元素。
# 实例1:威胁数量文案动态变化 — "There are currently 1 threats"# 数量会变,精确匹配不到,用正则匹配前缀assert_element(poco_selector={"textMatches":PocoElements.THREAT_COUNT_TEXT_REGEX},timeout=AppConfig.TIMEOUT_MEDIUM,msg="威胁数量文本未显示")# 实例2:多属性组合定位(如有必要)assert_element(poco_selector={"text":"Scan Center","name":"nav_item"},timeout=AppConfig.TIMEOUT_LONG,msg="导航项不存在")② 文本断言(text)— 静态文案
适用于:文案固定不变的按钮、标题、状态描述。
# 实例:扫描成功后的固定状态描述assert_element(text=PocoElements.SUCCESS_DESCRIPTION,# "There are no threats at the moment"timeout=AppConfig.TIMEOUT_SCAN,msg="扫描成功描述未显示")③ 图片断言(img)— 无文字/无 ID 的图标
适用于:只有图片、没有文字和 ID 的场景(如盾牌对勾图标、警告图标)。
# 实例:扫描结果页的盾牌对勾图标assert_element(img="resources/images/threat.png",timeout=AppConfig.TIMEOUT_VERY_LONG,msg="未检测到威胁警告图标")3、写一条用例的完整流程
以"快速扫描成功"为例,从零到一。
步骤 1:准备图像模板(仅当需要 img 断言时)
把要断言的图标截图,放到resources/images/,命名语义化:
resources/images/
├── threat.png # 威胁页警告图标
├── home_quick_scan_btn.png
└── quick_scan_sucess.png
步骤 2:在 PocoElements 定义文案常量
utils/poco_elements.py:
classPocoElements:SUCCESS_DESCRIPTION="There are no threats at the moment"UNINSTALL_BUTTON_TEXT="Uninstall"# 动态文案用正则THREAT_COUNT_TEXT_REGEX="There are currently.*"步骤 3:在 Page 类封装操作
pages/home_page.py:
classHomePage(BaseAction):defclick_quick_scan(self):self.go_to_scan_center()self.click_by_text(PocoElements.SCAN_CENTER_QUICK_SCAN_TEXT,timeout=AppConfig.TIMEOUT_LONG)步骤 4:写测试用例
testcases/test_quick_scan_with_data.py:
@allure.title("快速扫描成功")deftest_quick_scan_success(self):# 1. 数据准备TestDataUtils.clean_virus_from_scan()# 2. 执行操作self.home_page.click_quick_scan()# 3. 断言(固定文案 → text)assert_element(text=PocoElements.SUCCESS_DESCRIPTION,timeout=AppConfig.TIMEOUT_SCAN,msg="扫描结果未显示安全状态")四、快速运行
1、配置Android设备
- 启用开发者选项和USB调试
- 连接设备到电脑
- 验证连接:
adb devices
2、 运行测试
使用run.py(推荐)
python run.py此命令会:
- ✅ 执行所有测试用例
- ✅ 生成Allure测试结果数据
- ✅ 自动生成Allure HTML报告
3、查看报告
使用view_report.py
python view_report.py会自动打开最新的Allure报告。