Selenium结合pytest构建自动化测试框架:用例管理与断言

温以宁
温以宁
发布时间:2026-11-15| 14人浏览过
原创

本文介绍如何利用 pytest 的 fixture、参数化机制以及 Selenium Manager,将零散的 Selenium 脚本重构为结构清晰、易于维护的自动化测试工程。通过显式等待和 Page Object 模式分离页面交互与业务断言,提升测试稳定性与可读性。

将 Selenium 脚本纳入 pytest 管理体系的核心,并非简单地将操作封装为函数,而是明确划分浏览器生命周期、页面交互逻辑与业务断言的职责边界。若登录步骤、元素定位器及断言逻辑散落在测试函数中,一旦页面改版,大量用例会变得脆弱难护。下文将以登录页为例,演示如何合理拆分代码,其中涉及的元素 ID、提示文案及登录路径均视为需根据实际应用替换的约定配置。

先把零散脚本拆成稳定的项目边界

最基础的脚本往往将启动浏览器、访问页面、输入凭证、点击按钮及验证结果全部堆砌在一个函数内。虽然代码简短,但涉及重复登录流程的用例会导致定位器冗余复制,且若断言失败,浏览器的清理退出逻辑极易被遗漏。pytest 提供的测试发现、fixture 机制及参数化功能,恰好适合将这些职责解耦。

初期项目可采用如下目录结构进行组织:

selenium_tests/
├── pages/
│   └── login_page.py
├── tests/
│   └── test_login.py
├── conftest.py
└── pytest.ini

tests/用于存放测试用例,pages/负责封装页面交互逻辑,conftest.py则提供共享的 fixture。在项目起步阶段,无需过早引入复杂的基类或插件;待重复代码增多且维护痛点显现时,再逐步抽取公共层。

Selenium结合pytest构建自动化测试框架:用例管理与断言

把测试、页面对象与共享fixture分开放置

Selenium 4 的 Python 绑定内置了 Selenium Manager,可自动管理匹配的浏览器驱动,因此基础项目通常可直接从 webdriver.Chrome() 开始,无需手动下载驱动。前提是本地已安装对应浏览器,且首次解析驱动时网络通畅;若 CI 环境无法联网或需使用预装驱动,则需根据环境特定配置驱动路径。

浏览器的创建与清理应交由 fixture 管理。将作用域设为 function,确保每条测试用例拥有独立的 driver 实例,从而避免 Cookie、窗口状态及页面数据相互污染。yield 之后的清理逻辑具备强制性,即使测试断言失败也会执行:

# conftest.py
import pytest
from selenium import webdriver

@pytest.fixture
def driver():
    browser = webdriver.Chrome()
    try:
        yield browser
    finally:
        browser.quit()

尽管 pytest 默认 fixture 作用域即为函数级,此处显式声明有助于团队成员直观理解浏览器实例不会跨用例共享。若为了节省启动时间将浏览器提升至 session 级,必须妥善处理登录态、测试数据隔离及失败后的残留状态,否则性能提升可能以引入顺序相关的偶发失败为代价。

用显式等待控制异步页面,用页面对象集中改动

WebDriver 执行点击后,页面的请求与渲染可能仍在进行中。使用固定的 sleep(2) 仅是对页面加载完成的猜测:环境较快时造成无谓等待,环境较慢时仍可能因读取过早而失败。显式等待通过轮询明确条件,满足即继续,超时才报错。应避免混用隐式等待与显式等待,以防等待时长不可控。

传统写法常将等待逻辑与断言混杂在测试代码中:

import time

time.sleep(2)
message = driver.find_element(By.ID, "message").text
assert message == expected

若提示消息尚未渲染完成,元素查找便会失败;单纯延长固定等待时间只能掩盖竞态条件,并拖慢所有成功用例的执行速度。改为针对可见状态的显式等待,可确保测试仅在真正需要检查的页面状态就绪后继续执行。

页面对象应仅封装页面操作与数据读取,业务断言仍需保留在测试函数中。以下 username、password、login、message 均为示例应用中的 HTML 元素 ID,实际使用时需根据被测页面的具体属性进行调整:

# pages/login_page.py
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

class LoginPage:
    def __init__(self, driver):
        self.driver = driver

    def login(self, username, password):
        self.driver.find_element(By.ID, "username").send_keys(username)
        self.driver.find_element(By.ID, "password").send_keys(password)
        self.driver.find_element(By.ID, "login").click()

    def message_text(self):
        message = WebDriverWait(self.driver, 10).until(
            EC.visibility_of_element_located((By.ID, "message"))
        )
        return message.text

将等待逻辑置于 message_text() 中,是因为该操作描述了读取页面消息前需满足的状态条件;若目标页面通过 URL 跳转或其他标志表示加载完成,则应将等待条件调整为对应状态。Page Object Model 的价值在于集中管理定位器与页面交互,当页面结构变更时,通常只需修改对应的页面对象。切勿在页面对象中吞掉测试断言,否则会导致失败位置模糊,难以辨识业务意图。

Selenium结合pytest构建自动化测试框架:用例管理与断言

fixture负责浏览器清理,显式等待关注页面状态

用参数化管理用例,用测试函数表达断言

将每组输入数据与预期结果拆分为独立用例,可使 pytest 分别报告登录成功、失败等不同场景的结果。页面对象负责执行填写与提交操作,测试函数负责验证结果。其中的账号、错误消息及 TEST_LOGIN_URL 均为示例约定,接入实际测试环境时需替换为真实数据和地址:

# tests/test_login.py
import os
import pytest
from pages.login_page import LoginPage

@pytest.mark.parametrize(
    "username, password, expected",
    [
        ("alice", "valid-password", "欢迎,alice"),
        ("guest", "wrong-password", "用户名或密码错误"),
    ],
)
def test_login(driver, username, password, expected):
    driver.get(os.environ["TEST_LOGIN_URL"])
    page = LoginPage(driver)
    page.login(username, password)
    assert page.message_text() == expected

@pytest.mark.parametrize 会为每组参数生成独立的测试项;fixture 由测试参数 driver 请求,pytest 会在运行用例时自动创建并注入。当断言失败时,pytest 能精准报告具体的参数化用例,相比在单段脚本中循环多组数据,排查问题更为直接。测试环境的地址与凭据应通过环境变量或 CI 密钥注入,严禁将真实账号密码写入代码库。

保持运行入口的简洁性:

python -m pip install selenium pytest
python -m pytest

命令需在已激活的 Python 虚拟环境中执行,依赖版本应通过项目的依赖管理工具固定。若仅需运行特定文件,可将最后一行修改为 python -m pytest tests/test_login.py。如需更精细的失败定位,可后续增加日志、截图或 pytest 插件,无需在初版中就堆叠复杂的报告系统。

Selenium结合pytest构建自动化测试框架:用例管理与断言

参数化复用输入数据,断言留在测试函数

是否引入 Page Object 取决于页面交互的复用程度。若仅有一两个简短用例,直接写在测试中可能更清晰;当页面定位器大量重复、多个测试共享同一业务操作时,抽取页面对象更具性价比。维护自动化测试的核心在于确保用例独立性、等待条件对应真实页面状态,并将断言保留在能清晰表达业务预期的位置。

相关专题:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。