pytest+uiautomation+allure 数据驱动桌面自动化项目搭建指南-yaml版本

本文基于 pytest + uiautomation + allure 技术栈,搭建一套数据驱动(DDT)的 Windows 桌面应用自动化测试框架。彻底实现测试数据与业务代码分离,适配多组测试数据、批量回归测试,兼容企业级桌面客户端自动化场景,支持精美可视化测试报告生成。

一、技术栈说明

  • uiautomation:微软原生 Windows UI 自动化库,稳定无依赖,适配所有标准桌面控件

  • pytest:测试用例管理、执行、断言、数据驱动参数化核心框架

  • allure-pytest:生成交互式可视化测试报告,支持失败截图、用例分级、步骤展示

  • 数据驱动模式:独立存放测试数据,代码只写一次,批量执行多组测试场景,易维护、可复用

二、完整环境准备

1. 安装核心依赖库

bash 复制代码
# 安装自动化核心库、报告库、数据处理库
pip install pytest uiautomation allure-pytest pyyaml

2. Allure 报告工具安装(必备)

适配最新稳定版 Allure 2.41.0,修复旧版 XSS 漏洞、依赖兼容问题

  1. 下载地址:Allure 官方 Releases,选择 2.41.0 版本 Windows 安装包

  2. 解压压缩包,将内部 bin 目录配置到系统环境变量

  3. cmd 验证安装是否成功

bash 复制代码
allure --version

三、数据驱动版项目目录结构(工程化标准)

新增 data 测试数据目录,实现代码、数据、页面、用例完全解耦

plain 复制代码
desktop_automation/
├── config/                # 全局配置目录
│   └── setting.py         # 应用路径、等待时间、全局配置
├── data/                  # 【数据驱动核心】测试数据目录
│   └── notepad_data.yml   # yml格式测试用例数据
├── page/                  # PO页面对象层
│   ├── base_page.py       # 基础公共操作封装
│   └── notepad_page.py    # 业务页面控件&方法
├── testcase/              # 测试用例层(纯逻辑,无硬编码数据)
│   └── test_notepad.py    # 数据驱动测试用例
├── report/                # 自动生成测试报告
│   ├── temp/              # allure原始数据
│   └── html/              # 最终可视化报告
├── conftest.py            # pytest全局钩子、失败截图
└── pytest.ini             # pytest全局配置

四、全局配置文件

config/setting.py

python 复制代码
# 被测应用配置
APP_PATH = "notepad.exe"
# 全局隐式等待时间
IMPLICIT_WAIT = 3
# 测试数据文件路径
TEST_DATA_PATH = "./data/notepad_data.yml"

五、数据驱动核心:测试数据文件

采用 YAML 存储测试数据,支持多组场景、测试描述、预期结果,无需修改代码即可新增/删除用例

data/notepad_data.yml

yaml 复制代码
# 记事本输入测试-数据驱动
test_input_data:
  - case_name: "普通文本输入测试"
    input_content: "pytest+uiautomation 桌面自动化"
    expect_content: "pytest+uiautomation 桌面自动化"

  - case_name: "特殊符号输入测试"
    input_content: "测试123!@#$%^&*()"
    expect_content: "测试123!@#$%^&*()"

  - case_name: "空内容输入测试"
    input_content: ""
    expect_content: ""

  - case_name: "长文本输入测试"
    input_content: "数据驱动自动化测试,代码与数据分离,高效维护用例"
    expect_content: "数据驱动自动化测试,代码与数据分离,高效维护用例"

六、PO页面封装层

1. 基础公共页面 page/base_page.py

封装所有桌面应用通用操作,统一等待、点击、输入、截图、元素判断方法,所有业务页面继承此类

python 复制代码
import uiautomation as auto
import time
from config.setting import IMPLICIT_WAIT

class BasePage:
    def __init__(self):
        # 全局控件查找间隔,防止操作过快报错
        auto.SetGlobalSearchInterval(0.1)
        auto.SetGlobalSearchTimeout(IMPLICIT_WAIT)
        self.app_window = None

    def start_app(self, app_path: str):
        """启动桌面应用"""
        auto.Run(app_path)
        time.sleep(IMPLICIT_WAIT)

    def get_window(self, window_name: str):
        """定位应用主窗口"""
        self.app_window = auto.WindowControl(Name=window_name, searchDepth=1)
        return self.app_window

    def close_app(self):
        """关闭应用窗口"""
        if self.app_window and self.app_window.Exists(0):
            self.app_window.Close()
            time.sleep(1)

    def click_control(self, control, wait_time=1):
        """通用控件点击方法"""
        if control.WaitForExist(wait_time):
            control.Click()
            time.sleep(0.5)

    def input_text(self, control, text: str, wait_time=1):
        """通用文本输入方法"""
        if control.WaitForExist(wait_time):
            control.SendKeys(text)
            time.sleep(0.5)

    def get_control_text(self, control):
        """获取控件文本内容"""
        if control.WaitForExist(1):
            return control.Name if control.Name else control.DocumentText
        return ""

2. 业务页面 page/notepad_page.py

仅封装页面控件和业务方法,不写测试数据、不写断言,完全解耦

python 复制代码
import uiautomation as auto
from page.base_page import BasePage

class NotePadPage(BasePage):
    def __init__(self):
        super().__init__()
        # 页面控件定位
        self.window_name = "无标题 - 记事本"
        self.edit_area = auto.EditControl(searchDepth=2)

    def input_edit_content(self, content: str):
        """记事本输入指定内容"""
        self.input_text(self.edit_area, content)

    def get_edit_content(self):
        """获取记事本输入框内容"""
        return self.get_control_text(self.edit_area)

七、数据驱动测试用例层

核心改造点:通过 pytest 读取 YAML 数据,参数化批量执行用例,代码复用,数据灵活配置

testcase/test_notepad.py

python 复制代码
import pytest
import yaml
from page.notepad_page import NotePadPage
from config.setting import APP_PATH, TEST_DATA_PATH

# 读取YAML测试数据
def get_test_data():
    with open(TEST_DATA_PATH, "r", encoding="utf-8") as f:
        data = yaml.safe_load(f)
    return data["test_input_data"]

class TestNotePadDDT:
    # 全局前置:启动应用
    def setup_class(self):
        self.page = NotePadPage()
        self.page.start_app(APP_PATH)
        self.page.get_window(self.page.window_name)

    # 全局后置:关闭应用
    def teardown_class(self):
        self.page.close_app()

    # 数据驱动参数化执行
    @pytest.mark.parametrize("case", get_test_data(), ids=lambda x: x["case_name"])
    def test_notepad_input_ddt(self, case):
        """记事本多场景数据驱动输入测试"""
        # 从数据文件读取参数
        input_content = case["input_content"]
        expect_content = case["expect_content"]

        # 执行业务操作
        self.page.input_edit_content(input_content)
        actual_content = self.page.get_edit_content()

        # 断言校验
        assert actual_content == expect_content, f"用例失败:预期{expect_content},实际{actual_content}"

八、全局钩子与配置

conftest.py(失败自动截图+allure绑定)

python 复制代码
import pytest
import allure
import uiautomation as auto

# 用例失败自动截图并嵌入allure报告
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    report = outcome.get_result()
    # 仅用例执行阶段失败时截图
    if report.when == "call" and report.failed:
        try:
            pic = auto.CaptureToImage()
            allure.attach(pic, name="失败截图", attachment_type=allure.attachment_type.PNG)
        except Exception as e:
            print(f"截图失败:{str(e)}")

pytest.ini(全局运行配置)

ini 复制代码
[pytest]
# 用例扫描路径
testpaths = testcase
# 用例文件命名规则
python_files = test_*.py
# 测试类命名规则
python_classes = Test*
# 测试方法命名规则
python_functions = test_*
# 运行参数 + allure原始数据输出路径
addopts = -vs --alluredir=./report/temp --clean-alluredir

九、项目运行命令

1. 执行所有数据驱动用例

bash 复制代码
pytest

2. 生成并打开Allure可视化报告

bash 复制代码
# 生成静态报告
allure generate ./report/temp -o ./report/html --clean
# 打开报告页面
allure open ./report/html

十、uiautomation元素定位核心方法

1. 定位工具(必备)

  • 系统自带工具:C:\\Program Files \(x86\)\\Windows Kits\\10\\bin\\x64\\inspect\.exe

  • 轻量化工具:命令行执行 python \-m uiautomation\.inspect

  • 核心抓取属性:AutomationId(最优)、Name、ClassName、ControlType

2. 优先级排序(从稳到次)

  1. AutomationId:唯一固定标识,适配动态窗口,优先使用

  2. Name:显示文本,适合固定文案按钮、标签

  3. 层级嵌套定位:父窗口+子控件,解决重名控件问题

  4. 模糊匹配:NameContains 适配动态变化文本

  5. foundIndex下标:适配同类型多个控件

3. 常用控件定位示例

python 复制代码
# 主窗口
auto.WindowControl(Name="应用窗口名")
# 输入框
auto.EditControl(AutomationId="inputId")
# 按钮
auto.ButtonControl(Name="确认")
# 文本标签
auto.TextControl(Name="账号")
# 复选框
auto.CheckBoxControl(Name="记住密码")

十一、数据驱动框架核心优势

  1. 低耦合易维护:测试数据独立存放,新增场景无需修改代码,仅编辑YAML文件

  2. 批量高效执行:单条用例逻辑,批量多组数据执行,大幅减少冗余代码

  3. 报告清晰:allure报告按用例名称区分每组数据执行结果,失败自动截图溯源

  4. 适配企业场景:可扩展登录、表单、弹窗、列表等多业务数据驱动场景

  5. 稳定性强:基于微软原生UI接口,无图像识别偏差,适配绝大多数Windows客户端

十二、常见问题解决方案

  • 元素定位失败:增大 searchDepth 层级、开启全局等待、先定位父窗口再找子控件

  • 用例执行过快报错:调整全局隐式等待时间,控件操作增加显性等待

  • allure报告为空 :执行 pytest 必须携带 \-\-alluredir 参数,清理旧数据

  • YAML数据读取失败:保证文件编码为utf-8,格式缩进规范

总结

本框架基于数据驱动模式 完成全套桌面自动化搭建,彻底区分 配置层、数据层、页面层、用例层,完全符合企业级自动化工程规范。可直接迁移适配ERP、后台客户端、办公软件等所有Windows桌面应用,只需替换控件定位和测试数据即可快速落地批量回归测试。

相关推荐
乘云数字DATABUFF1 天前
5分钟部署开源APM Databuff:OpenTelemetry全链路追踪入门实战
运维·后端
荣--3 天前
一键部署不是为了省时间 —— 它是把"买来的 PaaS"变成"自己的平台"的拐点
运维·zabbix·工程化·一键部署·平台化·边界设计
江华森3 天前
动手实战学 Docker — 从零到集群编排完全指南
运维
Avan_菜菜4 天前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https
SelectDB5 天前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode6 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220707 天前
如何搭建本地yum源(上)
运维
大树8810 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠10 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质10 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务