news 2026/7/5 6:53:41

基于Selenium与Pytest的自动化测试框架搭建实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Selenium与Pytest的自动化测试框架搭建实战指南

1. 项目概述

“快速搭建Selenium测试框架”这个标题,听起来像是每个刚接触自动化测试的同学都想立刻实现的目标。我做了十多年测试,从手动点点点到用脚本模拟操作,再到搭建和维护成体系的测试框架,这个过程里踩过的坑、绕过的弯路,足够写好几本书了。今天,我就以一个过来人的身份,和你聊聊怎么真正“快速”地把一个Selenium测试框架给搭起来,让它不只是能跑几个脚本,而是成为一个稳定、可维护、能融入团队工作流的工程化产物。

很多人一听到“框架”就觉得头大,以为要搞一堆复杂的设计模式和高深架构。其实没那么玄乎。简单说,一个测试框架的核心目标就三个:让测试脚本写起来更简单、跑起来更稳定、结果看起来更清晰。Selenium WebDriver是那个帮你“操纵浏览器”的利器,但它本身只是个库。框架要做的事,就是围绕WebDriver,把环境管理、用例组织、数据驱动、报告生成、异常处理这些脏活累活都封装好,让你能专注于写业务测试逻辑。所以,咱们今天聊的“快速搭建”,重点不在“快”字上盲目求速,而在“搭建”的路径选择上,让你用最少的步骤,避开最常见的陷阱,得到一个马上就能用、并且方便后续扩展的坚实基础。

2. 框架核心设计思路与选型考量

2.1 为什么是“Selenium + Pytest”组合?

从你给的热词里能看到,pytest测试框架python自动化测试框架是高频关联词。这不是偶然。在Python生态里,Pytest几乎是自动化测试的事实标准,它和Selenium是黄金搭档。

我早期也用过unittest,但后来全面转向了Pytest,原因很实在:

  1. 写起来更简洁:不用写一堆setUptearDown,一个fixture就能搞定各种前置后置操作,复用性极高。
  2. 断言更智能:直接用Python的assert语句,失败时Pytest能给出非常详细的差异对比,查错效率翻倍。
  3. 插件生态丰富:需要生成漂亮报告?有pytest-htmlallure-pytest。需要控制用例并行?有pytest-xdist。几乎你能想到的增强功能,都有现成的轮子。
  4. 筛选与参数化超级方便:用@pytest.mark标记用例,想跑哪个跑哪个。@pytest.mark.parametrize做数据驱动测试,代码简洁到没朋友。

所以,我们框架的技术栈基石就定下来了:Python 3.7+, Selenium 4.x, Pytest。这是经过大量项目验证过的、最稳定高效的组合。

2.2 浏览器与驱动管理:告别手动下载的烦恼

selenium安装selenium有安装的必要吗?还是安装浏览器插件就行这类问题,反映了环境配置这个最初的拦路虎。Selenium 4的一个巨大进步就是引入了Selenium Manager

以前,我们需要根据Chrome/Firefox的版本,去网上找对应版本的chromedrivergeckodriver,手动下载、配置PATH,版本不对就报错,非常麻烦。现在,从Selenium 4.6版本开始,只要你正确安装了selenium库,当你创建webdriver.Chrome()webdriver.Firefox()时,Selenium Manager会在后台自动检查你的浏览器版本,并下载匹配的驱动程序。这简直是新手的福音!

注意:虽然Selenium Manager很方便,但在公司内网环境或需要严格版本控制的场景下,可能仍需手动指定驱动路径。我们的框架设计需要兼容这两种模式。

2.3 框架要解决哪些具体问题?

一个裸奔的Selenium脚本只能算玩具。一个框架需要系统性地解决以下问题:

  • 环境隔离:每个测试用例都应该在一个干净、独立的环境中开始,避免用例间相互污染。
  • 失败处理:脚本失败时不能直接崩溃,要有截图、日志记录,方便事后排查。
  • 等待机制:网络延迟、页面加载慢导致元素找不到,是自动化失败的主要原因之一,必须有稳健的等待策略。
  • 代码复用:页面元素定位器、常用操作(如登录、跳转)必须抽象出来,避免重复代码。
  • 测试数据管理:账号、密码、测试URL等不应该硬编码在脚本里。
  • 报告直观:跑完测试,生成一份谁都能看懂的HTML报告,是向团队展示价值的关键。

我们的快速搭建,就是围绕解决这几个问题来展开的。

3. 项目结构与核心模块拆解

参考热词中提到的pycharm selenium pytest自动化框架分层目录,一个清晰的项目结构是框架可维护性的基石。不要把所有代码都堆在一个文件里。我推荐如下目录结构:

selenium_framework_demo/ ├── configs/ # 配置文件目录 │ ├── __init__.py │ └── settings.py # 全局配置:浏览器类型、超时时间、基础URL等 ├── data/ # 测试数据目录 │ └── test_data.yaml # 或 .json, .csv 文件 ├── logs/ # 运行时日志目录(.gitignore忽略) ├── reports/ # 测试报告目录(.gitignore忽略) ├── pages/ # 页面对象模型(Page Object)目录 │ ├── __init__.py │ ├── base_page.py # 所有页面类的基类 │ └── login_page.py # 示例:登录页面 ├── test_cases/ # 测试用例目录 │ ├── __init__.py │ └── test_login.py # 示例:登录测试用例 ├── conftest.py # Pytest核心配置文件,定义fixture ├── utilities/ # 工具函数目录 │ ├── __init__.py │ ├── logger.py # 日志记录模块 │ └── helper.py # 通用辅助函数,如截图、文件读取 └── requirements.txt # Python依赖包列表

这个结构的好处是职责分离。configs管配置,data管数据,pages管页面元素和操作,test_cases只管测试逻辑,utilities提供各种工具。conftest.py是Pytest的魔法所在,里面定义的fixture可以被所有用例自动调用。

4. 一步步搭建框架核心

4.1 初始化项目与依赖管理

首先,创建一个新的项目文件夹,并初始化虚拟环境。我强烈建议使用虚拟环境来隔离项目依赖。

# 创建项目目录 mkdir selenium_framework_demo && cd selenium_framework_demo # 创建虚拟环境(以venv为例) python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # Linux/Mac: source venv/bin/activate

然后,创建requirements.txt文件,写入我们的核心依赖:

# requirements.txt selenium>=4.10.0 pytest>=7.0.0 pytest-html>=3.2.0 # 用于生成HTML报告 pytest-xdist>=3.0.0 # 可选,用于并行测试 pyyaml>=6.0 # 用于读取yaml格式的测试数据 webdriver-manager # 备用驱动管理工具,如果Selenium Manager在某些环境下失效

使用pip安装:

pip install -r requirements.txt

4.2 编写核心配置与工具类

1. 全局配置 (configs/settings.py)这里定义框架运行所需的所有可配置项。

# configs/settings.py import os from pathlib import Path # 项目根目录 BASE_DIR = Path(__file__).parent.parent # 浏览器类型:chrome, firefox, edge BROWSER = "chrome" # 是否启用无头模式(不显示浏览器界面) HEADLESS = False # 隐式等待时间(秒) IMPLICIT_WAIT = 10 # 页面加载超时时间(秒) PAGE_LOAD_TIMEOUT = 30 # 基础测试URL BASE_URL = "https://www.example.com" # 请替换为你的测试地址 # 路径配置 LOG_DIR = BASE_DIR / "logs" REPORT_DIR = BASE_DIR / "reports" SCREENSHOT_DIR = REPORT_DIR / "screenshots" # 确保目录存在 for dir_path in [LOG_DIR, REPORT_DIR, SCREENSHOT_DIR]: dir_path.mkdir(parents=True, exist_ok=True)

2. 日志模块 (utilities/logger.py)良好的日志是调试的灯塔。我们配置一个同时输出到控制台和文件的logger。

# utilities/logger.py import logging import sys from pathlib import Path from configs.settings import LOG_DIR def get_logger(name, level=logging.INFO): """获取一个配置好的logger实例""" logger = logging.getLogger(name) # 避免重复添加handler if logger.handlers: return logger logger.setLevel(level) # 格式器 formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) # 控制台处理器 console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(formatter) logger.addHandler(console_handler) # 文件处理器(按天滚动,可选用logging.handlers.TimedRotatingFileHandler) log_file = LOG_DIR / f"{name}.log" file_handler = logging.FileHandler(log_file, encoding='utf-8') file_handler.setFormatter(formatter) logger.addHandler(file_handler) return logger # 创建一个默认的框架logger framework_logger = get_logger("selenium_framework")

3. 通用辅助函数 (utilities/helper.py)这里放一些会被频繁调用的函数,比如截图。

# utilities/helper.py import time from pathlib import Path from configs.settings import SCREENSHOT_DIR from utilities.logger import framework_logger def take_screenshot(driver, name=None): """ 截取屏幕截图并保存到报告目录。 :param driver: WebDriver实例 :param name: 截图文件名,不包含扩展名 :return: 截图文件的相对路径(用于嵌入报告) """ if name is None: name = f"screenshot_{int(time.time())}" filename = f"{name}.png" filepath = SCREENSHOT_DIR / filename driver.save_screenshot(str(filepath)) framework_logger.info(f"截图已保存至: {filepath}") # 返回相对路径,方便HTML报告引用 return f"./screenshots/{filename}"

4.3 设计页面对象模型(Page Object)

Page Object模式是Selenium自动化测试的最佳实践,核心思想是将页面元素定位和操作封装成类,测试用例只调用这些类的方法,不与具体的定位器(如XPath)耦合。这样,当页面UI改动时,你只需要修改对应的Page类,而不需要修改大量测试用例。

1. 基类 (pages/base_page.py)基类封装所有页面都会用到的公共操作,比如元素查找、等待、点击、输入等。

# pages/base_page.py from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException, NoSuchElementException from utilities.logger import framework_logger from configs.settings import IMPLICIT_WAIT, PAGE_LOAD_TIMEOUT class BasePage: """所有页面对象的基类""" def __init__(self, driver): self.driver = driver self.driver.implicitly_wait(IMPLICIT_WAIT) self.driver.set_page_load_timeout(PAGE_LOAD_TIMEOUT) self.logger = framework_logger self.wait = WebDriverWait(self.driver, IMPLICIT_WAIT) def find_element(self, locator): """查找单个元素,加入显式等待和日志""" try: self.logger.debug(f"正在查找元素: {locator}") element = self.wait.until(EC.presence_of_element_located(locator)) self.logger.debug(f"元素找到: {locator}") return element except TimeoutException: self.logger.error(f"查找元素超时: {locator}") raise def find_elements(self, locator): """查找多个元素""" try: self.logger.debug(f"正在查找多个元素: {locator}") elements = self.wait.until(EC.presence_of_all_elements_located(locator)) self.logger.debug(f"找到 {len(elements)} 个元素: {locator}") return elements except TimeoutException: self.logger.warning(f"查找多个元素超时,可能未找到: {locator}") return [] def click(self, locator): """点击元素""" element = self.find_element(locator) self.logger.info(f"点击元素: {locator}") element.click() def input_text(self, locator, text): """向元素输入文本""" element = self.find_element(locator) self.logger.info(f"向元素 {locator} 输入文本: {text}") element.clear() element.send_keys(text) def get_text(self, locator): """获取元素的文本""" element = self.find_element(locator) text = element.text self.logger.info(f"获取元素 {locator} 的文本: {text}") return text def is_element_visible(self, locator, timeout=5): """判断元素是否可见(自定义超时)""" try: WebDriverWait(self.driver, timeout).until( EC.visibility_of_element_located(locator) ) return True except TimeoutException: return False

2. 具体页面类示例 (pages/login_page.py)以登录页面为例,展示如何继承基类。

# pages/login_page.py from selenium.webdriver.common.by import By from pages.base_page import BasePage class LoginPage(BasePage): """登录页面""" # 定位器:将页面元素定位方式集中管理 # 使用 (By.ID, “value”) 或 (By.XPATH, “xpath_expression”) 的格式 USERNAME_INPUT = (By.ID, "username") PASSWORD_INPUT = (By.ID, "password") LOGIN_BUTTON = (By.XPATH, "//button[@type='submit']") ERROR_MESSAGE = (By.CLASS_NAME, "alert-error") def __init__(self, driver): super().__init__(driver) # 可以在这里添加页面特定的初始化,比如访问登录页URL # self.driver.get(f"{BASE_URL}/login") def login(self, username, password): """执行登录操作""" self.logger.info(f"尝试登录,用户名: {username}") self.input_text(self.USERNAME_INPUT, username) self.input_text(self.PASSWORD_INPUT, password) self.click(self.LOGIN_BUTTON) def get_error_message(self): """获取登录错误提示信息""" if self.is_element_visible(self.ERROR_MESSAGE): return self.get_text(self.ERROR_MESSAGE) return None

实操心得:定位器是Page Object的核心。我强烈建议优先使用IDNAME,因为它们通常最稳定。其次是CSS Selector,它比XPath更易读、性能通常也更好。XPath虽然强大,但容易因页面结构微小变动而失效,应谨慎使用,并避免使用绝对路径(以/开头)。

4.4 编写Pytest核心配置与Fixture

conftest.py是Pytest的本地插件文件,在这里定义的fixture可以被同一目录及子目录下的所有测试文件自动识别和使用。这是我们框架的“粘合剂”。

# conftest.py import pytest from selenium import webdriver from selenium.webdriver.chrome.options import Options as ChromeOptions from selenium.webdriver.firefox.options import Options as FirefoxOptions from configs.settings import BROWSER, HEADLESS, BASE_URL from utilities.logger import framework_logger from utilities.helper import take_screenshot @pytest.fixture(scope="function") def driver(): """ 核心Fixture:为每个测试函数提供一个新的WebDriver实例。 scope="function" 表示每个测试用例都会重新创建和关闭浏览器,保证用例隔离。 """ driver = None browser_name = BROWSER.lower() try: if browser_name == "chrome": options = ChromeOptions() if HEADLESS: options.add_argument("--headless=new") # Selenium 4.8+ 推荐写法 options.add_argument("--no-sandbox") options.add_argument("--disable-dev-shm-usage") options.add_argument("--disable-gpu") options.add_argument("--window-size=1920,1080") # 禁用“Chrome正受到自动测试软件控制”的提示 options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('useAutomationExtension', False) # 关键:让Selenium Manager自动管理驱动 driver = webdriver.Chrome(options=options) elif browser_name == "firefox": options = FirefoxOptions() if HEADLESS: options.add_argument("--headless") driver = webdriver.Firefox(options=options) elif browser_name == "edge": # Edge类似Chrome配置 from selenium.webdriver.edge.options import Options as EdgeOptions options = EdgeOptions() if HEADLESS: options.add_argument("--headless") driver = webdriver.Edge(options=options) else: raise ValueError(f"不支持的浏览器类型: {browser_name}") framework_logger.info(f"启动 {browser_name} 浏览器成功") driver.maximize_window() driver.get(BASE_URL) yield driver # 将driver对象传递给测试用例 except Exception as e: framework_logger.error(f"初始化WebDriver失败: {e}") pytest.fail(f"WebDriver初始化失败: {e}") finally: # 测试结束后,无论成功失败,都关闭浏览器 if driver: driver.quit() framework_logger.info("浏览器已关闭") @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): """ Pytest钩子函数:用于在测试失败时自动截图。 这个函数比较高级,但非常实用。它会在每个测试步骤(setup, call, teardown)后生成报告。 我们只在测试执行(call)失败时截图。 """ outcome = yield report = outcome.get_result() # 如果当前阶段是'call'(即测试执行本身)且测试失败了 if report.when == "call" and report.failed: # 尝试从测试用例的fixture中获取driver对象 for name, fixture_value in item.funcargs.items(): if name == "driver" and hasattr(fixture_value, 'save_screenshot'): # 生成截图,文件名包含测试用例名 screenshot_path = take_screenshot(fixture_value, f"failure_{item.name}") # 将截图路径添加到测试报告的长文本中,pytest-html插件会读取 if hasattr(report, 'extra'): from pytest_html import extras # 这里需要pytest-html插件的extras功能 # 更通用的做法是直接保存,并在conftest中配置pytest-html的asset_dir # 我们采用另一种方式:在pytest命令行参数中配置--html报告的asset目录 pass # 简单起见,我们已经在take_screenshot函数中记录了日志 framework_logger.error(f"测试失败,截图已保存: {screenshot_path}") break

这个conftest.py做了几件关键事:

  1. driverfixture:负责浏览器的创建和销毁。scope="function"确保每个测试用例都是独立的。
  2. 集中管理浏览器选项:比如无头模式、窗口大小、禁用自动化提示等。
  3. 自动截图钩子:在测试失败时自动截屏,这对排查界面问题至关重要。

4.5 编写第一个测试用例

现在,我们可以用封装好的Page Object和Fixture来写一个清晰、易读的测试用例了。

# test_cases/test_login.py import pytest from pages.login_page import LoginPage # 假设我们有一个主页类 # from pages.home_page import HomePage class TestLogin: """登录功能测试集""" def test_login_success(self, driver): """测试登录成功""" login_page = LoginPage(driver) # 调用页面对象的方法执行操作 login_page.login("valid_username", "valid_password") # 断言:登录后应该跳转到首页,或者出现某个成功元素 # 例如:assert HomePage(driver).is_user_logged_in() is True # 这里先用一个简单的标题断言示例 assert "Dashboard" in driver.title print("登录成功测试通过") @pytest.mark.parametrize("username, password, expected_error", [ ("", "password123", "用户名不能为空"), ("admin", "", "密码不能为空"), ("wrong", "wrong", "用户名或密码错误"), ]) def test_login_failure(self, driver, username, password, expected_error): """测试登录失败的各种情况(数据驱动)""" login_page = LoginPage(driver) login_page.login(username, password) # 获取实际的错误信息 actual_error = login_page.get_error_message() # 断言错误信息符合预期 assert actual_error is not None assert expected_error in actual_error print(f"登录失败测试通过: {username}/{password} -> {expected_error}")

看,测试用例变得多清爽!你完全不用关心浏览器怎么开、元素怎么等、失败怎么截图。你只需要关注测试逻辑:给定什么输入,执行什么操作,期望什么结果

4.6 运行测试并生成报告

框架搭好了,用例写好了,最后一步就是运行它并得到一份漂亮的报告。

最简单的方式,在项目根目录下创建一个run_tests.py脚本,或者直接使用命令行。

命令行运行(推荐):

# 运行所有测试 pytest # 运行特定测试文件 pytest test_cases/test_login.py # 运行带有特定标记的测试(例如标记为‘smoke’的冒烟测试) pytest -m smoke # 并行运行测试(需要pytest-xdist) pytest -n auto # 运行并生成HTML报告 pytest --html=reports/test_report.html --self-contained-html

--self-contained-html参数会让生成的HTML报告把所有CSS、JS都打包进去,变成一个独立的文件,方便分享。

更专业的配置 (pytest.ini)你可以在项目根目录创建一个pytest.ini文件来固化常用配置,这样就不用每次敲长长的命令了。

# pytest.ini [pytest] # 自动发现测试文件的路径 testpaths = test_cases # 测试文件名的模式 python_files = test_*.py # 测试类名的模式 python_classes = Test* # 测试函数名的模式 python_functions = test_* # 添加命令行默认选项 addopts = --strict-markers --html=reports/test_report.html --self-contained-html -v # 定义自定义标记 markers = smoke: 冒烟测试用例 regression: 回归测试用例 slow: 运行缓慢的测试用例

有了这个文件,你只需要在终端输入pytest,它就会自动按照配置执行测试并生成报告。

5. 高级主题与避坑指南

5.1 元素定位与等待策略

这是Selenium自动化失败的重灾区。热词里提到了selenium定位元素.元素为空鼠标操,这很可能是因为元素还没加载出来就进行操作。

1. 抛弃time.sleep()新手最爱用time.sleep(10),这是最糟糕的做法。它固定等待,无论元素是否早已出现,都浪费了时间;如果网络慢,10秒可能还不够。我们应该使用智能等待

2. 显式等待 (Explicit Wait)我们已经在BasePagefind_element方法中使用了WebDriverWait。这是最佳实践。它的原理是:在指定的超时时间内,每隔一段时间(默认0.5秒)检查一次条件是否成立(如元素可见、可点击),一旦成立就立即返回,否则超时抛出异常。

# 更灵活的显式等待示例 from selenium.webdriver.support.expected_conditions import element_to_be_clickable def wait_for_element_clickable(self, locator, timeout=10): """等待元素可点击""" try: element = WebDriverWait(self.driver, timeout).until( element_to_be_clickable(locator) ) return element except TimeoutException: self.logger.error(f"元素在{timeout}秒内未变为可点击状态: {locator}") # 这里可以加入截图 raise

3. 定位器策略优先级

  • 首选ID/Name:唯一且稳定。
  • 其次CSS Selector:性能好,语法简洁。例如#username(ID选择器),.btn-primary(类选择器),input[type='submit'](属性选择器)。
  • 谨慎使用XPath:尽量避免绝对路径(/html/body/div[1]/...)。使用相对路径和属性组合,如//button[contains(@class, 'submit-btn') and text()='登录']。XPath对于动态ID或复杂结构有时是唯一选择。

5.2 处理弹窗、iframe和文件上传

弹窗 (Alert/Confirm/Prompt)

from selenium.webdriver.common.alert import Alert # 切换到弹窗并接受(确定) alert = Alert(driver) alert.accept() # 取消(否定) alert.dismiss() # 输入文本(针对Prompt) alert.send_keys("输入的文字")

iframe操作iframe内的元素前,必须先切换到对应的iframe。

# 通过ID或Name切换 driver.switch_to.frame("iframe_id_or_name") # 通过WebElement切换 iframe_element = driver.find_element(By.TAG_NAME, "iframe") driver.switch_to.frame(iframe_element) # 操作完成后切回主文档 driver.switch_to.default_content()

文件上传如果上传按钮是<input type="file">,直接使用send_keys传入文件绝对路径即可。

upload_element = driver.find_element(By.XPATH, "//input[@type='file']") upload_element.send_keys("/path/to/your/file.jpg")

如果遇到非input标签的复杂上传组件,可能需要借助AutoITpyautogui等桌面自动化工具,但这会降低脚本的可移植性。

5.3 数据驱动测试

我们的test_login_failure用例已经使用了Pytest内置的@pytest.mark.parametrize装饰器,这是最简单直接的数据驱动方式。对于更复杂的数据(比如从Excel、YAML、JSON读取),可以结合使用。

例如,使用YAML文件管理测试数据 (data/login_data.yaml):

# data/login_data.yaml login_success: - username: "admin" password: "correct_password" expected_title: "Dashboard" login_failure: - username: "" password: "any" expected_error: "用户名不能为空" - username: "admin" password: "wrong" expected_error: "密码错误"

然后在测试用例中读取:

import yaml import pytest def load_login_data(): with open('data/login_data.yaml', 'r', encoding='utf-8') as f: data = yaml.safe_load(f) return data class TestLoginWithYAML: @pytest.mark.parametrize("case", load_login_data()['login_failure']) def test_login_fail_with_yaml(self, driver, case): login_page = LoginPage(driver) login_page.login(case['username'], case['password']) assert case['expected_error'] in login_page.get_error_message()

5.4 常见问题排查(避坑实录)

问题1:selenium.common.exceptions.WebDriverException: Message: unknown error: cannot find Chrome binary

  • 原因:Chrome浏览器没有安装在默认路径,或者根本没安装。
  • 解决:确保Chrome已安装。如果安装在非标准路径,需要通过options.binary_location指定。
    options.binary_location = r"C:\Program Files\Google\Chrome\Application\chrome.exe"

问题2:selenium.common.exceptions.SessionNotCreatedException: This version of ChromeDriver only supports Chrome version XX

  • 原因:Chrome浏览器版本和ChromeDriver驱动版本不匹配。
  • 解决:这是Selenium Manager要解决的核心问题。如果它失效,可以:
    1. 手动下载匹配的驱动,并在代码中指定路径:webdriver.Chrome(executable_path='/path/to/chromedriver', options=options)(Selenium 4.10后executable_path已弃用,建议用Service类)。
    2. 使用webdriver-manager库(已在requirements.txt中作为备用)。
      from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.chrome.service import Service service = Service(ChromeDriverManager().install()) driver = webdriver.Chrome(service=service, options=options)

问题3:元素找到了,但点击或输入没反应?

  • 原因:元素可能被遮挡(如弹窗、另一个div)、不在可视区域、或者需要JavaScript点击。
  • 解决
    1. 使用ActionChains模拟更真实的操作。
      from selenium.webdriver.common.action_chains import ActionChains element = login_page.find_element(LoginPage.LOGIN_BUTTON) ActionChains(driver).move_to_element(element).click().perform()
    2. 滚动元素到视图中。
      driver.execute_script("arguments[0].scrollIntoView(true);", element)
    3. 尝试用JavaScript直接点击。
      driver.execute_script("arguments[0].click();", element)

问题4:测试在本地跑得好好的,一上CI(如Jenkins)就失败?

  • 原因:CI服务器通常是Linux无图形界面环境,需要无头模式,且可能缺少浏览器依赖库。
  • 解决
    1. 确保在CI配置中设置了HEADLESS = True
    2. 对于Linux服务器(如Ubuntu),可能需要安装浏览器运行库。
      # 对于Chrome sudo apt-get update sudo apt-get install -y wget curl unzip xvfb libxi6 libgconf-2-4 sudo apt-get install -y fonts-liberation libasound2 libnspr4 libnss3 libxss1 xdg-utils
    3. 考虑使用Docker镜像,里面已经配置好了所有环境,这是最干净、最一致的方案。

6. 框架的扩展与优化方向

一个基础的框架搭建完成后,可以根据项目需求不断扩展:

  1. 集成API测试:结合requests库,一个测试用例里同时验证前端交互和后端接口。
  2. 测试报告增强:集成Allure框架,生成更美观、交互性更强的报告,包含步骤详情、截图、附件等。
  3. 持续集成/持续部署 (CI/CD):将测试框架接入Jenkins、GitLab CI、GitHub Actions等,实现代码提交后自动触发测试。
  4. 分布式测试:使用Selenium GridSelenium 4Distributed模式,在多台机器、多种浏览器上并行运行测试,极大缩短测试总时间。
  5. 移动端测试:Appium的核心原理与Selenium WebDriver一致(基于W3C标准),学会了Selenium,再学Appium会非常快。
  6. Playwright/Cypress对比:如热词所示,可以了解playwright selenium pyppeteer对比Playwright是后起之秀,由微软开发,支持多浏览器且自带强大的自动等待和录制功能,在某些场景下比Selenium更稳定高效。但对于Web自动化测试入门和大量现有项目维护,Selenium庞大的社区和生态依然是巨大优势。

搭建框架不是一蹴而就的,而是一个迭代的过程。从今天这个清晰、可用的基础版本开始,在实践中遇到什么问题,就解决什么问题,逐步将它打磨成最适合你团队业务的利器。记住,最好的框架不是最复杂的那个,而是最能提升你和团队效率的那个。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/5 6:53:06

seedance2.0边缘设备降速根因与调优指南

1. 项目概述&#xff1a;这不是一次简单的“变慢”&#xff0c;而是一场典型的服务演进阵痛 “怎么看待seedance2.0降速到几乎不可用&#xff1f;”——这句话最近在不少内容创作者、独立开发者和中小团队的技术交流群里反复出现&#xff0c;语气里带着困惑、焦虑&#xff0c;…

作者头像 李华
网站建设 2026/7/5 6:50:40

魔兽争霸3终极优化指南:WarcraftHelper让经典游戏重获新生

魔兽争霸3终极优化指南&#xff1a;WarcraftHelper让经典游戏重获新生 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 魔兽争霸3作为一款经典即时战略…

作者头像 李华
网站建设 2026/7/5 6:49:57

Mermaid Live Editor:实时图表编辑的现代化解决方案

Mermaid Live Editor&#xff1a;实时图表编辑的现代化解决方案 【免费下载链接】mermaid-live-editor Edit, preview and share mermaid charts/diagrams. New implementation of the live editor. 项目地址: https://gitcode.com/GitHub_Trending/me/mermaid-live-editor …

作者头像 李华
网站建设 2026/7/5 6:49:14

从冒泡到传送带流水线:一个3D沉浸式算法靶场,让思想的伟力改变世界

距离上次写博客已有很长的时间&#xff0c;我也已经近一年没学算法了。最近期末考突然捡起算法与数据结构&#xff0c;以往的痛苦又开始折磨我&#xff0c;使我意识到算法可视化的迫切需求。于是我建了一个这样的项目——一个能让我"看见"算法执行过程的平台。 学算法…

作者头像 李华
网站建设 2026/7/5 6:48:33

程序员就业:2026 年还能靠什么拿到,从问题拆解到交付验证

《程序员就业&#xff1a;2026 年还能靠什么拿到&#xff0c;从问题拆解到交付验证》看起来是个大话题&#xff0c;但真落到项目里&#xff0c;常常就是几个具体选择。下面我尽量按实际开发时会遇到的问题来讲。摘要这篇面向准备找工作、跳槽或转型的程序员&#xff0c;但不会把…

作者头像 李华