没有理想的人不伤心

前端 UI 自动化框架 —— playwright

2025/10/26
6
0

image.png|500

1 框架搭建

playwright 官方文档:https://playwright.dev/python/docs/intro#installing-playwright-pytest

playwright官方提供了 pytest-playwright 包,支持通过 python 语言写前端自动化

下面来搭建前端 UI 自动化测试框架,需要考虑项目结构、配置文件、测试用例编写、运行方式等部分

1.1 目录结构

一个规范的框架结构应便于维护测试用例、配置、公共方法等,推荐结构如下:

playwright_ui_auto/
├── config/                  # 配置文件目录
│   ├── env.py               # 环境配置(如测试/生产环境 URL)
│   └── settings.py          # 框架全局设置(如超时时间、截图路径等)
├── tests/                   # 测试用例目录(pytest 默认识别该目录)
│   ├── conftest.py          # pytest 夹具(fixture)配置(公共资源)
│   ├── test_login.py        # 登录模块测试用例
│   └── test_search.py       # 搜索模块测试用例
├── common/                  # 公共工具类目录
│   ├── page_base.py         # 页面基类(封装通用操作:点击、输入等)
│   └── logger.py            # 日志工具
├── reports/                 # 测试报告目录(自动生成)
├── screenshots/             # 截图目录(失败时自动保存)
├── pytest.ini               # pytest 配置文件(指定参数、插件等)
└── requirements.txt         # 项目依赖清单(可选,用于环境复刻)

1.2 核心配置

1.2.1 pytest.ini

用于指定测试目录、默认命令行参数、报告格式等,示例:

[pytest]
testpaths = tests                  # 测试用例存放目录
pythonpath = .                     # 项目根目录加入环境变量(避免导入模块报错)
addopts = -vs --html=reports/report.html  # 运行时默认参数:-vs 显示详细日志,生成 HTML 报告
markers =
    smoke: 冒烟测试用例            # 标记用例(如 @pytest.mark.smoke)
    login: 登录模块测试

1.2.2 config/env.py

管理不同环境的 URL,避免硬编码到测试用例:

# 环境配置:开发/测试/生产环境的基础 URL
ENV_CONFIG = {
    "dev": "https://dev.example.com",
    "test": "https://test.example.com",
    "prod": "https://example.com"
}

# 默认使用测试环境
DEFAULT_ENV = "test"
BASE_URL = ENV_CONFIG[DEFAULT_ENV]

1.2.3 tests/conftest.py

利用 pytest 的 fixture 机制,封装公共资源(如浏览器实例、页面实例),避免重复初始化:

import pytest
from playwright.sync import Page, Browser
from config.env import BASE_URL

# 定义浏览器夹具(scope="session" 表示整个测试会话只启动一次浏览器)
@pytest.fixture(scope="session")
def browser(playwright):
    # 启动浏览器(headless=False 表示显示浏览器窗口,便于调试)
    browser = playwright.chromium.launch(headless=False)
    yield browser
    browser.close()  # 测试结束后关闭浏览器

# 定义页面夹具(每个测试用例前打开新页面)
@pytest.fixture(scope="function")
def page(browser: Browser):
    page = browser.new_page()
    page.goto(BASE_URL)  # 打开默认环境的 URL
    yield page
    page.close()  # 测试结束后关闭页面

fixture(翻译为 固定装置、夹具)的含义:指在测试执行前设置的环境或状态,以确保测试能够在一致和可控的条件下进行

用于:1 测试环境的准备;2 测试数据的设置;3 清理工作

2 playwright 基础功能

文档:https://playwright.dev/python/docs/writing-tests

2.1 测试用例编写

测试文件名、函数名都需要以 test_ 为前缀

示例:test_example.py

import re
from playwright.sync_api import Page, expect

def test_has_title(page: Page):
    page.goto("https://playwright.dev/")

    # Expect a title "to contain" a substring.
    expect(page).to_have_title(re.compile("Playwright"))

def test_get_started_link(page: Page):
    page.goto("https://playwright.dev/")

    # Click the get started link.
    page.get_by_role("link", name="Get started").click()

    # Expects page to have a heading with the name of Installation.
    expect(page.get_by_role("heading", name="Installation")).to_be_visible()

2.2 导航主页面

大多数测试从导航到页面的 URL 开始,然后与页面的元素进行交互

page.goto(“https://playwright.dev/”)

Playwright 回等待页面加载完成后再继续操作

2.3 定位元素

playwright 使用 locators API 来实现定位元素

Playwright 会自动等待元素可操作后再执行操作,因此无需显式的等待元素可用。

locators API:https://playwright.dev/python/docs/locators

示例:

# Create a locator.
get_started = page.get_by_role("link", name="Get started")

# Click it.
get_started.click()

# 写成一行
page.get_by_role("link", name="Get started").click()

常用定位函数:

locator.check() 勾选输入复选框
locator.click() 单击元素
locator.uncheck() 取消选中输入复选框
locator.hover() 将鼠标悬停在元素上
locator.fill() 填写表单字段,输入文本
locator.focus() 聚焦元素
locator.press() 按单个键
locator.set_input_files() 上传文件
locator.select_option() 在下拉菜单中选择选项

2.4 断言

Playwright 包含一些断言,这些断言会等到预期条件满足后再执行。使用这些断言可以使测试更加稳定且更具弹性。例如,以下代码将等到页面获取到包含“Playwright”的标题

import re
from playwright.sync_api import expect

expect(page).to_have_title(re.compile("Playwright"))

断言API:https://playwright.dev/python/docs/test-assertions

常用断言函数

expect(locator).to_be_checked() 复选框已选中
expect(locator).to_be_enabled() 控制已启用
expect(locator).to_be_visible() 元素可见
expect(locator).to_contain_text() 元素包含文本
expect(locator).to_have_attribute() 元素具有属性
expect(locator).to_have_count() 元素列表已指定长度
expect(locator).to_have_text() 元素匹配文本
expect(locator).to_have_value() 输入元素有值
expect(page).to_have_title() 页面有标题
expect(page).to_have_url() 页面有 url

2.5 测试隔离

使用 Playwright 编写的测试在浏览器上下文的隔离干净环境中执行。这种隔离模型提高了可重复性,并防止了级联测试失败。

playwright pytest 插件基于 测试fixture 的概念

测试隔离是指每个测试与其他测试完全隔离。每个测试都独立运行。这意味着每个测试都有自己的本地存储、会话存储、Cookie 等。Playwright 使用 BrowserContext 来实现这一点,这些 BrowserContext 相当于类似隐身模式的配置文件。它们创建速度快、成本低,并且完全隔离,即使在单个浏览器中运行也是如此。Playwright 为每个测试创建一个上下文,并在该上下文中提供一个默认页面

如下面的两个测试函数也是环境隔离的,每个page都是独立的

from playwright.sync_api import Page

def test_example_test(page: Page):
  pass
  # “page” 属于一个独立的浏览器上下文,用于指定的测试

def test_another_test(page: Page):
  pass
  # 第二个 page 完全独立于第一个 page

测试隔离官方说明:https://playwright.dev/python/docs/browser-contexts

2.6 fixtures 使用

fixture 用于在测试之前或之后执行代码,并在测试之间共享对象,就是安排好各个步骤和数据,是测试完成任务的基础。

如果想使得所有测试都以来的fixture(固定装置),autouse fixtures 提供了此功能

autouse fixtures:https://docs.pytest.org/en/6.2.x/fixture.html#autouse-fixtures-fixtures-you-don-t-have-to-request

我们可以通过将 autouse=True 传递给 Fixture 的装饰器,使 Fixture 成为自动使用 Fixture。以下是一个简单的使用示例,其中 append_first 是一个autouse fixture,因此即使在两个测试函数中没有显式调用,也会自动被调用

# contents of test_append.py
import pytest


@pytest.fixture
def first_entry():
    return "a"


@pytest.fixture
def order(first_entry):
    return []


@pytest.fixture(autouse=True)
def append_first(order, first_entry):
    return order.append(first_entry)


def test_string_only(order, first_entry):
    assert order == [first_entry]


def test_string_and_int(order, first_entry):
    order.append(2)
    assert order == [first_entry, 2]

3 codegen 生成用例

Playwright 具有开箱即用生成测试的功能,是快速开始测试的绝佳方式。它会打开两个窗口:一个浏览器窗口,您可以在其中与要测试的网站进行交互;另一个是 Playwright 检查器窗口,您可以在其中记录测试、复制测试、清除测试以及更改测试语言。

测试生成器:https://playwright.dev/python/docs/codegen

额外参数:请参考上面的文档

  • 使用 --device 选项模拟移动设备时记录脚本和测试,该选项设置视口大小和用户代理等。

  • 使用 --color-scheme 选项模拟配色方案时记录脚本和测试。

  • 使用 --timezone 、 --geolocation 和 --lang 选项模拟时区、语言和位置,录制脚本和测试

  • 使用 --save-storage 运行 codegen 以在会话结束时保存 cookieslocalStorageIndexedDB 数据

  • 等。。。

3.1 开始录制

运行 codegen 命令启动用例生成器,参数为URL,可选

playwright codegen [url]

会自动打开浏览器指定网页,并打开一个操作录制器

在浏览器中操作后,录制器会记录下操作并自动生成对应交互代码

image.png

3.2 录制时的功能按钮

image.png|300

1 拖拽功能条

2 开始/暂停录制

3 pick locator:元素定位,会自动定位元素

4 assert visibility:断言元素可见

5 assert text:断言元素包含特定文本

6 assert value:断言元素具有特定值

7 assert snapshot:断言元素具有指定快照

3.3 录制器功能按钮

out.png

image.png|50:复制当前代码框中生成的代码

image.png|50:clear,清楚代码并重新开始录制

target:生成的代码语言,有python、java、nodejs、json等

image.png|40:录制器主题,夜间模式

3.4 结束录制

当在浏览器中的所有操作完成后,检查生成的代码,并自行粘贴到自己的代码中,然后关闭即可(不会自动保存)

4 运行和调试

参考:https://playwright.dev/python/docs/running-tests

运行(无头模式,即不打开任何浏览器窗口,结果显示在终端):pytest [测试文件…]

参数:https://playwright.dev/python/docs/test-runners

  • –head,测试时会打开浏览器窗口

  • –browser [浏览器名称],指定浏览器运行测试

  • -k [测试函数名],运行特定的测试函数

  • –numprocesses [num],指定测试进程数,并行运行测试

调试:https://playwright.dev/python/docs/debug

bash:PWDEBUG=1  pytest -s [文件名…],打开playwright inspector进行调试

调试特定测试函数:

  • -k [测试函数…]

5 跟踪查看器

https://playwright.dev/python/docs/trace-viewer

Playwright Trace Viewer 是一个 GUI 工具,可让您探索测试的记录的 Playwright 跟踪,这意味着您可以前后移动测试的每个操作,并直观地查看每个操作期间发生的情况。

记录跟踪:pytest --tracing on

option:

  • off:默认,不打开跟踪

  • on:打开跟踪

  • retain-on-failure:删除成功的测试用例的跟踪,只保留失败的

跟踪记录根据文档所述,存放在 test-results/ 目录下的trace.zip

我咋没找到嘞

打开跟踪记录

方式一:终端打开:playwright show-trace trace.zip

方式二:浏览器访问:trace.playwright.dev

6 自动化测试方法论

从本质上讲,测试的本质是行动和断言

根据 pytest 给出的描述,https://docs.pytest.org/en/6.2.x/fixture.html#autouse-fixtures-fixtures-you-don-t-have-to-request

测试分为四个步骤:

  1. arrange(统筹安排)

  2. act(行为动作)

  3. assert(断言)

  4. cleanup(清理)

6.1 Arrange

首先为测试做好一切的准备,这几乎涵盖了除了 “Act” 之外的所有步骤。它就像排列多米诺骨牌,以便动作能够在一个状态改变的步骤中完成。这可能意味着准备对象、启动/终止服务、将记录录入数据库,甚至包括定义要查询的 URL、为尚不存在的用户生成凭证,或者只是等待某个进程完成。

6.2 Act

想要测试的某个动作,可能会产生状态的变化,观察以及通过断言来判断行为获得结果,行为通常定义为函数

6.3 Assert

断言,观察 Act 的最终状态,并检查是否符合预期。

6.4 Cleanup

测试的收尾工作,以确保其他测试不会受影响