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

本UI自动化测试框架采用Page Object设计模式,结合Airtest图像识别和Poco

UI自动化技术,实现稳定可靠的自动化测试。

🛠️ 技术栈:

一、环境安装

1、安装本地airtest Python环境

plain 复制代码
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):

plain 复制代码
# 先安装 Scoop(如果尚未安装)
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
irm get.scoop.sh | iex

scoop install allure

二、搭建测试框架

这里以一个核心功能为快速扫描病毒的安卓TV应用项目为例,来搭建UI自动化测试框架

1、框架结构

plain 复制代码
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、 常用命令

bash 复制代码
# 安装依赖
pip install -r requirements.txt

# 运行所有测试
python run.py

# 运行指定测试文件
pytest testcases/test_quick_scan.py -v

# 运行带标记的测试
pytest -m smoke          # 冒烟测试
pytest -m critical       # 关键测试

# 生成Allure报告
allure generate reports/allure_results -o reports/allure_report --clean

# 查看报告
allure open reports/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(兜底)

python 复制代码
def assert_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断言
    if text or poco_selector:
        poco = PocoManager.get_instance()
        start = time.time()

        while time.time() - start <= timeout:
            try:
                if text and poco(text=text).exists():
                    _log("Poco断言成功")
                    return True
                # poco_selector 为字典选择器(如 {"text": "xx", "name": "yy"}),
                # 必须用 ** 解包为关键字参数;整体作为位置参数传入会抛异常并被下方 except 静默吞掉
                if poco_selector and poco(**poco_selector).exists():
                    _log("Poco断言成功")
                    return True
            except Exception:
                pass
            time.sleep(interval)

        _log("Poco未命中")

    # fallback到图片断言
    if img:
        try:
            # 等待图片出现
            pos = wait(Template(img), timeout=timeout)
            if pos:
                _log("图片断言成功")
                return pos
        except Exception:
            _log("图片断言未命中")

    # 失败处理
    if snapshot_on_fail:
        file = _screenshot("assert_fail", test_name)
        _log(f"截图: {file}")

    raise AssertionError(f"{msg} | text={text} | img={img}")

2、三种用法及适用场景

① Poco 选择器断言(poco_selector)--- 最推荐

适用于:动态文本、需要多条件组合定位的元素。

python 复制代码
# 实例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)--- 静态文案

适用于:文案固定不变的按钮、标题、状态描述。

python 复制代码
# 实例:扫描成功后的固定状态描述
assert_element(
    text=PocoElements.SUCCESS_DESCRIPTION,  # "There are no threats at the moment"
    timeout=AppConfig.TIMEOUT_SCAN,
    msg="扫描成功描述未显示"
)

③ 图片断言(img)--- 无文字/无 ID 的图标

适用于:只有图片、没有文字和 ID 的场景(如盾牌对勾图标、警告图标)。

python 复制代码
# 实例:扫描结果页的盾牌对勾图标
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:

python 复制代码
class PocoElements:
    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:

python 复制代码
class HomePage(BaseAction):
    def click_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:

python 复制代码
@allure.title("快速扫描成功")
def test_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. 验证连接:

    bash 复制代码
    adb devices

2、 运行测试

使用run.py(推荐)
bash 复制代码
python run.py

此命令会:

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

3、查看报告

使用view_report.py
bash 复制代码
python view_report.py

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

相关推荐
刘胡子大叔1 小时前
Docker 容器名 ping 不通
运维·docker·容器
工业传感笔记1 小时前
粉体车间浮尘工况下的光电传感器选型:三类干扰机理与分层适配方案
其他·自动化
a5986521 小时前
Docker多开云手机,六边云独立端口隔离访问实战
android·运维·docker·容器·智能手机·云手机
戴西软件1 小时前
企业如何搭建自己的AI智能体?戴西智能体管理与戴西SKILL管理实战解析
运维·jvm·人工智能·自动化·rpa
qq_284274052 小时前
《机械制造工艺学》复习课:典型表面加工路线 · 工序安排四原则 · 加工余量与工艺尺寸链
自动化·制造
疯狂的维修2 小时前
工业相机的镜头如何分辨景深
数码相机·自动化
wei091302 小时前
2026 企业 AI 办公工具选型指南:搭建 AI 与现有办公流程融合体系
大数据·运维·人工智能
ggaofeng2 小时前
如何配置snat(让内网访问外网)和dnat(将外网请求转发到内网服务器)
运维·服务器·snat·dnat·局域网访问外网·外网访问局域网
yyuuuzz2 小时前
云服务器搭建个人博客记录:一次访问超时的复盘
运维·服务器·数据库