ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

UI自动化-Airtest框架落地实战

UI自动化-Airtest框架落地实战

本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-clear

4、测试报告

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设备

  1. 启用开发者选项和USB调试
  2. 连接设备到电脑
  3. 验证连接:
    adb devices

2、 运行测试

使用run.py(推荐)
python run.py

此命令会:

  • ✅ 执行所有测试用例
  • ✅ 生成Allure测试结果数据
  • ✅ 自动生成Allure HTML报告

3、查看报告

使用view_report.py
python view_report.py

会自动打开最新的Allure报告。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进