当前位置:首页 > 技术 > 正文内容

构建高内聚低耦合的 Playwright UI 自动化测试架构

访客 技术 2026年6月8日 3

环境初始化与依赖管理

搭建基于 Python 的 Web UI 自动化测试平台,核心依赖于 Playwright 进行浏览器操作,Pytest 作为测试执行引擎,YAML 用于配置数据驱动,Allure 生成可视化报告。首先需在开发环境中安装必要的第三方库。

pip install pyyaml playwright allure-pytest pytest pytest-playwright
playwright install chromium

此外,需从官方 Maven 仓库下载 Allure Commandline 工具并配置至系统环境变量中,以支持报告的生成与浏览。

项目目录结构规划

遵循分层设计原则,将代码按功能职责进行划分,确保各模块间的低耦合性。标准工程结构如下:

project_root
├── common # 公共组件层
│ ├── action.py # 基础交互封装
│ ├── report.py # 异常截图与报告关联
│ └── config.py # 配置读取逻辑
├── tests # 测试用例层
│ ├── conftest.py # Pytest 钩子函数
│ └── test_core.py# 业务场景脚本
├── data # 测试数据层
│ └── scenario.yaml
├── logs # 日志输出目录
├── reports # Allure 报告存放区
└── main.py # 启动入口

公共组件层实现

1. 基础交互封装 (action.py)

提取高频使用的 DOM 操作,如定位、点击及输入,减少重复代码量。

from playwright.sync_api import Page

def execute_interact(page_obj: Page, selector: str, text_content: str):
    """
    统一处理元素定位与填充操作
    :param page_obj: 页面句柄
    :param selector: CSS 选择器或 XPath
    :param text_content: 待填入文本
    """
    element = page_obj.locator(selector)
    element.click()
    element.fill(text_content)

2. 结果捕获与关联 (report.py)

在测试失败或关键节点时截取屏幕图像,并嵌入到 Allure 报告中。

import os
import allure
from playwright.sync_api import Page

def capture_snapshot(ctx_page: Page, save_dir: str, report_id: str):
    filepath = f"{save_dir}{report_id}.png"
    ctx_page.screenshot(path=filepath)
    
    with open(filepath, 'rb') as img_file:
        allure.attach(img_file.read(), name=report_id, attachment_type=allure.attachment_type.PNG)
    os.remove(filepath) # 可选:清理临时文件

3. 配置文件加载 (config.py)

使用 PyYAML 解析外部数据文件,实现测试数据与脚本分离。

import yaml
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

def load_yaml_data(file_name: str) -> dict:
    file_path = BASE_DIR / "data" / file_name
    with open(file_path, encoding='utf-8') as stream:
        return yaml.safe_load(stream)

测试用例层设计

1. Pytest 钩子配置 (conftest.py)

利用 Hook 机制动态向 Allure 报告注入用例元数据(如特性名称和标题)。

import allure
from _pytest.nodes import Node

def pytest_runtest_call(item: Node):
    func_doc = item.function.__doc__
    parent_doc = getattr(getattr(item.parent, '_obj', None), '__doc__', '')
    
    if parent_doc:
        allure.dynamic.feature(parent_doc)
    if func_doc:
        allure.dynamic.title(func_doc)

2. 业务场景脚本 (test_core.py)

具体测试逻辑应清晰描述业务步骤,调用公共方法处理细节。

import pytest
import allure
from common.action import execute_interact
from common.report import capture_snapshot
from common.config import load_yaml_data
from playwright.sync_api import Page

@allure.epic("Web 搜索验证")
@allure.title("关键词检索功能测试")
def test_keyword_lookup(page: Page):
    doc = """验证百度首页搜索框的准确性"""
    # 注入文档字符串以适配 Allure
    test_keyword_lookup.__doc__ = doc 
    
    config_data = load_yaml_data("scenario.yaml")
    search_cfg = config_data.get("search_case")
    
    page.goto(search_cfg["url"])
    execute_interact(page, search_cfg["input_selector"], search_cfg["keyword"])
    page.get_by_role("button", name=search_cfg["submit_text"]).click()
    
    capture_snapshot(page, search_cfg["img_path"], search_cfg["report_name"])

@allure.epic("Web 搜索验证")
@allure.title("特定技术词检索")
def test_playwright_search(page: Page):
    page.goto("https://www.baidu.com/")
    execute_interact(page, "#kw", "playwright")
    page.get_by_role("button", name="百度一下").click()
    capture_snapshot(page, "./logs/screenshots/", "pw_check")

数据驱动层 (Data)

所有可变参数存入 YAML 文件,便于非技术人员维护或进行环境切换。

# data/scenario.yaml
search_case:
  url: https://www.baidu.com/
  input_selector: "#kw"
  keyword: pytest
  submit_text: 百度一下
  img_path: ./logs/screenshots/
  report_name: pytest_result

运行配置与报告生成

1. 框架配置 (pytest.ini)

[pytest]
addopts = -v --alluredir=./reports/temp --clean-alluredir
testpaths = tests
python_files = test_*.py
python_functions = test_*
markers =
    smoke: 标记为冒烟测试

2. 启动脚本 (main.py)

整合测试执行与报告发布流程,提供一键运行能力。

import subprocess
import sys

def run_tests():
    exit_code = subprocess.call([sys.executable, "-m", "pytest"])
    
    # 生成静态报告
    subprocess.call(["allure", "generate", "./reports/temp", "-o", "./reports/final", "--clean"])
    
    # 本地开启报告服务器查看
    subprocess.Popen(["allure", "serve", "./reports/temp"])
    
    return exit_code

if __name__ == "__main__":
    sys.exit(run_tests())

分层设计的核心价值

采用模块化分层架构主要基于以下考量:

  1. 维护效率:若仅需变更登录地址,只需修改配置层,无需遍历数百个用例代码。
  2. 扩展性:新增公共行为(如等待加载、右键菜单)时,仅在 Common 层添加,所有用例复用。
  3. 数据解耦:测试数据与逻辑代码分离,便于进行数据驱动测试(DDT),应对不同测试集。
  4. 可读性:清晰的目录结构使新成员能快速理解项目脉络,降低协作沟通成本。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。