基于Pytest与Selenium的电商UI自动化测试实战:从PageObject模式到CI/CD集成
1. 项目概述从“点”到“面”的UI自动化实战思维最近在团队内部做了一次关于UI自动化测试的分享主题就是围绕一个具体的电商项目——TPshop的前台门户网站来展开一次完整的实战演练。之所以选择这个项目是因为它足够典型一个标准的B2C电商门户包含了用户注册登录、商品浏览、搜索、购物车、下单支付模拟等核心业务流程。这些流程恰恰是UI自动化测试最能发挥价值的地方也是测试工程师在日常工作中最常需要覆盖的场景。很多朋友在刚开始接触UI自动化时容易陷入两个误区要么是沉迷于录制回放工具生成一堆脆弱且难以维护的脚本要么是过早地追求高大上的框架设计写了一堆抽象层但核心的业务验证逻辑却模糊不清。这次实战我想带大家走一条更务实的路以真实的业务场景为驱动从编写第一个稳定的测试用例开始逐步构建起可维护、可复用的自动化测试工程。我们的目标不是造一个完美的轮子而是解决实际项目中反复回归测试的痛点。TPshop作为一个开源项目其前台门户的功能模块清晰非常适合作为我们演练的“沙盘”。通过这个项目我们不仅能掌握Selenium、Pytest等工具的基本操作更能深入理解如何将零散的“点”单个操作串联成稳固的“线”业务流程最终编织成一张可靠的“面”测试套件。接下来我就把这次实战中的设计思路、关键步骤、踩过的坑以及总结的心得毫无保留地分享出来。2. 整体设计与框架选型为什么是Pytest Selenium PageObjects在启动任何自动化项目之前花时间在设计和选型上是绝对值得的。一个糟糕的架构会让后期的维护成本呈指数级增长。针对TPshop前台门户的UI自动化我核心考虑了以下几点并做出了相应的技术选型。2.1 核心需求与挑战分析TPshop前台门户的UI自动化主要面临以下几个挑战页面元素多且易变电商网站的页面元素非常丰富广告位、活动 banner、商品推荐等区域可能频繁调整。业务流程长且关联性强从浏览商品到成功下单是一个涉及多个页面的长流程测试脚本需要良好的状态管理和数据传递。测试数据依赖需要准备有效的用户账号、商品库存等测试执行前后可能需要清理数据。执行稳定性网络延迟、资源加载速度、弹窗广告等都可能导致脚本执行失败需要健壮的等待和异常处理机制。团队协作与可维护性脚本不是写给自己看的需要结构清晰方便其他同事阅读、修改和新增用例。基于这些挑战我放弃了使用无代码录制工具的想法因为它们生成的脚本通常耦合度高、难以应对变化。转而选择以代码为核心通过设计模式来提升脚本质量的方案。2.2 技术栈选型与理由1. 编程语言Python理由语法简洁学习曲线平缓拥有极其丰富的测试生态库Pytest, Selenium, Requests等。团队内部也以Python为主便于知识共享和代码评审。2. 测试框架Pytest理由相比Python自带的unittestPytest更灵活、强大。它支持参数化测试轻松实现多数据驱动、丰富的Fixture用于管理测试前置后置条件如浏览器启动/关闭、清晰的断言语法以及庞大的插件生态如生成美观的测试报告、控制用例执行顺序等。这些都是构建一个健壮自动化项目所必需的。3. 浏览器自动化工具Selenium WebDriver理由行业标准社区活跃支持所有主流浏览器。通过与浏览器驱动的配合可以模拟真实用户的所有操作。虽然新兴工具如Playwright、Cypress在某些方面有优势但Selenium的稳定性和普适性在当前阶段仍是首选。4. 设计模式Page Object Model (POM 页面对象模型)理由这是应对“页面元素易变”挑战的核心武器。POM模式将页面的元素定位和操作封装成独立的类Page Object测试脚本TestCase只调用这些页面对象提供的方法。当页面UI发生变化时我们只需要修改对应的Page Object类中的元素定位符而不需要改动大量的测试脚本极大地提升了可维护性。进阶在基础POM上我通常会引入Page Factory或自定义的BasePage类来进一步简化元素定位的初始化并封装一些公共操作如等待、截图、滚动等。5. 其他辅助工具WebDriver Manager自动管理浏览器驱动如chromedriver的下载和匹配避免手动下载和路径配置的麻烦。Allure Pytest用于生成详细、可视化的测试报告包含步骤截图、错误日志等便于问题定位。YAML/JSON用于管理测试配置如测试环境URL、账号信息和测试数据实现数据与代码的分离。注意不要试图在项目一开始就引入过于复杂的设计比如抽象出过多的层次。我的经验是先基于POM模式把主干流程跑通在迭代过程中当发现重复代码或维护痛点时再进行合理的抽象和重构。3. 工程结构搭建与核心模块解析一个清晰的项目结构是团队协作的基石。下面是我为TPshop UI自动化项目设计的目录结构并解释每个核心模块的职责。tpshop_ui_auto/ ├── configs/ # 配置文件目录 │ ├── __init__.py │ ├── config.yaml # 主配置文件环境、全局参数 │ └── test_data.yaml # 测试数据文件 ├── logs/ # 日志文件目录自动生成 ├── reports/ # 测试报告目录自动生成 ├── page_objects/ # 页面对象层 │ ├── __init__.py │ ├── base_page.py # 基类页面封装公共方法 │ ├── home_page.py # 首页 │ ├── login_page.py # 登录页 │ ├── goods_list_page.py # 商品列表页 │ ├── goods_detail_page.py # 商品详情页 │ ├── cart_page.py # 购物车页 │ └── order_page.py # 订单确认/支付页 ├── test_cases/ # 测试用例层 │ ├── __init__.py │ ├── conftest.py # Pytest的Fixture集中管理 │ ├── test_login.py # 登录相关用例 │ ├── test_browse_goods.py # 商品浏览相关用例 │ └── test_trade_flow.py # 核心交易流用例 ├── utils/ # 工具函数层 │ ├── __init__.py │ ├── driver_manager.py # 浏览器驱动管理 │ ├── file_reader.py # 文件读取工具读YAML等 │ ├── logger.py # 日志记录工具 │ └── common_actions.py # 通用操作封装 ├── fixtures/ # 自定义复杂Fixture可选 ├── requirements.txt # 项目依赖包列表 └── pytest.ini # Pytest配置文件3.1 核心模块深度解析1.base_page.py所有页面对象的“基石”这个文件是整个POM架构的核心。它定义了一个BasePage类其他所有具体的页面类如LoginPage都继承自它。它的主要职责是初始化驱动接收并保存WebDriver实例。封装显式等待这是提升脚本稳定性的关键。我封装了一个find_element方法内部使用Selenium的WebDriverWait和expected_conditions替代原生的find_element_by_*方法确保在元素出现、可点击、可见时才进行操作。封装常用操作如点击、输入、获取文本、截图等。在这些操作中加入日志和异常处理。提供页面通用验证比如验证页面标题、URL是否包含特定关键字。# utils/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 import logging class BasePage: def __init__(self, driver): self.driver driver self.logger logging.getLogger(__name__) self.timeout 10 # 默认等待超时时间 def find_element(self, locator): 查找单个元素加入显式等待 try: self.logger.info(f正在查找元素: {locator}) element WebDriverWait(self.driver, self.timeout).until( EC.presence_of_element_located(locator) ) return element except TimeoutException: self.logger.error(f查找元素超时: {locator}) self._take_screenshot(element_not_found) raise def click(self, locator): 点击元素确保元素可点击 element WebDriverWait(self.driver, self.timeout).until( EC.element_to_be_clickable(locator) ) element.click() self.logger.info(f已点击元素: {locator}) def input_text(self, locator, text): 向输入框输入文本先清空 element self.find_element(locator) element.clear() element.send_keys(text) self.logger.info(f已在元素 {locator} 输入: {text}) def _take_screenshot(self, name): 截图并保存用于错误排查 screenshot_path f./logs/screenshot_{name}_{datetime.now().strftime(%Y%m%d_%H%M%S)}.png self.driver.save_screenshot(screenshot_path) self.logger.info(f截图已保存至: {screenshot_path})2.conftest.py测试的“后勤总管”这是Pytest框架的一个特殊文件用于定义Fixture。Fixture可以理解为测试的“脚手架”用来管理测试用例的前置和后置条件。我们将浏览器生命周期管理、测试数据准备等都在这里定义。# test_cases/conftest.py 示例片段 import pytest from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.chrome.service import Service from utils.file_reader import read_yaml from page_objects.home_page import HomePage import logging pytest.fixture(scopesession) def config(): 读取全局配置整个测试会话只读一次 config_data read_yaml(./configs/config.yaml) return config_data pytest.fixture(scopefunction) # 每个测试函数执行一次 def driver(config): 初始化浏览器驱动这是最核心的Fixture options webdriver.ChromeOptions() # 根据配置决定是否无头运行 if config.get(headless): options.add_argument(--headless) options.add_argument(--disable-gpu) options.add_argument(--window-size1920,1080) # 使用WebDriver Manager自动管理驱动 service Service(ChromeDriverManager().install()) driver webdriver.Chrome(serviceservice, optionsoptions) driver.implicitly_wait(config.get(implicit_wait, 5)) # 隐式等待作为兜底 driver.get(config[base_url]) yield driver # 将driver对象提供给测试用例使用 # 测试函数执行完毕后执行清理工作 driver.quit() logging.info(浏览器已关闭) pytest.fixture def home_page(driver): 提供首页页面对象依赖driver fixture return HomePage(driver) pytest.fixture def login_page(driver): 提供登录页页面对象 from page_objects.login_page import LoginPage return LoginPage(driver)3. 配置文件 (config.yaml) 与测试数据 (test_data.yaml)将易变的数据和配置从代码中分离出来是提升脚本适应性的重要一步。# configs/config.yaml base_url: http://demo.tpshop.cn/ # TPshop演示地址 headless: false # 是否无头模式调试时设为false implicit_wait: 3 # 隐式等待时间秒 explicit_wait: 10 # 显式等待超时时间秒 browser: chrome test_user: username: test_autoexample.com password: 123456# configs/test_data.yaml login: success: - {username: test_autoexample.com, password: 123456, expected: 我的账户} failure: - {username: wrongexample.com, password: 111111, expected: 账号密码错误} goods_search: - {keyword: 手机, expected_count_min: 1} - {keyword: 不存在的商品xyz, expected_count_min: 0}4. 页面对象Page Object实现详解以TPshop的登录功能和商品加入购物车流程为例展示如何实现具体的页面对象。4.1 登录页面 (login_page.py) 实现登录页面通常包含用户名输入框、密码输入框、登录按钮以及可能的错误信息提示区域。# page_objects/login_page.py from .base_page import BasePage from selenium.webdriver.common.by import By import logging class LoginPage(BasePage): # 1. 定义页面元素定位器Locators # 使用元组 (定位方式, 定位表达式) 是标准做法 USERNAME_INPUT (By.ID, username) # 假设ID实际需根据TPshop页面分析 PASSWORD_INPUT (By.ID, password) LOGIN_BUTTON (By.XPATH, //button[contains(text(), 登录)]) ERROR_MSG_SPAN (By.CLASS_NAME, error-message) SUCCESS_MSG_AREA (By.LINK_TEXT, 我的账户) # 登录成功后的跳转指示 # 2. 初始化方法 def __init__(self, driver): super().__init__(driver) # 调用父类BasePage的初始化 self.logger logging.getLogger(__name__) # 3. 定义页面操作行为方法 def enter_username(self, username): 输入用户名 self.input_text(self.USERNAME_INPUT, username) return self # 返回自身支持链式调用 def enter_password(self, password): 输入密码 self.input_text(self.PASSWORD_INPUT, password) return self def click_login_button(self): 点击登录按钮 self.click(self.LOGIN_BUTTON) def get_error_message(self): 获取登录错误提示信息如果存在 try: # 快速判断错误元素是否存在设置较短超时 element WebDriverWait(self.driver, 3).until( EC.presence_of_element_located(self.ERROR_MSG_SPAN) ) return element.text except TimeoutException: return None # 没有错误信息 def is_login_success(self, expected_text我的账户): 判断是否登录成功通过检查成功后的页面元素 try: element WebDriverWait(self.driver, self.timeout).until( EC.presence_of_element_located(self.SUCCESS_MSG_AREA) ) return expected_text in element.text except TimeoutException: return False # 4. 定义完整的业务场景方法可选但推荐 def login(self, username, password): 完整的登录流程 self.logger.info(f执行登录操作用户名: {username}) self.enter_username(username) self.enter_password(password) self.click_login_button() # 可以在这里加入页面跳转的等待或者返回下一个页面的对象 # 例如登录成功后跳转到首页可以返回HomePage实例 # from .home_page import HomePage # return HomePage(self.driver)4.2 商品详情页与购物车页面联动商品加入购物车是一个涉及两个页面的流程。我们首先在商品详情页执行“加入购物车”操作然后通常会跳转到购物车页面进行确认。# page_objects/goods_detail_page.py class GoodsDetailPage(BasePage): ADD_TO_CART_BUTTON (By.ID, add_cart) CART_ICON (By.CLASS_NAME, cart-icon) def add_to_cart(self): 点击加入购物车按钮 self.click(self.ADD_TO_CART_BUTTON) # 加入成功后页面上可能有提示这里可以加入一个成功提示的等待 # 例如WebDriverWait(...).until(EC.text_to_be_present_in_element((By.ID, msg), 添加成功)) self.logger.info(商品已加入购物车) # 加入购物车后通常还在本页面或者跳转到购物车页。这里我们设计为返回购物车页面对象 from .cart_page import CartPage return CartPage(self.driver) # 假设点击后跳转到购物车页 # page_objects/cart_page.py class CartPage(BasePage): CART_ITEM_LIST (By.CLASS_NAME, cart-item) CHECKOUT_BUTTON (By.LINK_TEXT, 去结算) def get_cart_items_count(self): 获取购物车中商品项的数量 items self.find_elements(self.CART_ITEM_LIST) # BasePage需补充find_elements方法 return len(items) def proceed_to_checkout(self): 点击去结算按钮 self.click(self.CHECKOUT_BUTTON) from .order_page import OrderPage return OrderPage(self.driver)实操心得在定义页面对象的方法时特别是涉及页面跳转的要明确方法的返回值。返回self表示仍停留在当前页面返回另一个PageObject实例则清晰地告诉了调用者操作完成后进入了哪个新页面。这能让测试用例的流程阅读起来像自然语言一样流畅。5. 测试用例编写与Pytest特性应用有了坚实的页面对象层编写测试用例就变得非常直观和简洁。我们使用Pytest来组织这些用例。5.1 基础测试用例示例# test_cases/test_login.py import pytest from utils.file_reader import read_yaml # 读取测试数据 test_data read_yaml(./configs/test_data.yaml) class TestLogin: 登录功能测试类 # 测试用例登录成功 def test_login_success(self, driver, login_page): 使用有效账号密码登录验证登录成功 # 1. 跳转到登录页 (假设从首页有入口这里简化处理) driver.get(http://demo.tpshop.cn/index.php?mHomecUseralogin) # 2. 执行登录操作 login_page.enter_username(test_autoexample.com) login_page.enter_password(123456) login_page.click_login_button() # 3. 断言验证 assert login_page.is_login_success(), 登录成功后未找到‘我的账户’元素登录可能失败 # 测试用例登录失败 - 使用参数化 pytest.mark.parametrize(login_data, test_data[login][failure]) def test_login_failure(self, driver, login_page, login_data): 使用错误账号密码登录验证正确的错误提示 driver.get(http://demo.tpshop.cn/index.php?mHomecUseralogin) login_page.enter_username(login_data[username]) login_page.enter_password(login_data[password]) login_page.click_login_button() # 断言错误信息是否符合预期 actual_error login_page.get_error_message() assert actual_error is not None, 未出现预期的错误提示信息 assert login_data[expected] in actual_error, f错误提示不符。预期包含‘{login_data[expected]}’实际是‘{actual_error}’5.2 核心业务流程测试用例这是UI自动化的价值体现将多个页面操作串联起来验证完整的用户旅程。# test_cases/test_trade_flow.py import pytest from page_objects.home_page import HomePage class TestTradeFlow: 核心交易流程测试浏览商品 - 加入购物车 - 去结算 pytest.mark.order(1) # 使用pytest-ordering插件控制顺序但应谨慎使用 def test_add_goods_to_cart(self, driver, home_page): 测试将商品加入购物车 # 1. 首页搜索商品 search_keyword 手机 goods_list_page home_page.search_goods(search_keyword) # 2. 进入第一个商品详情页 goods_detail_page goods_list_page.click_first_goods() # 3. 加入购物车 cart_page goods_detail_page.add_to_cart() # 4. 验证购物车商品数量增加 # 这里需要一个前置条件购物车初始为空。实际项目中可能需要先清空购物车。 assert cart_page.get_cart_items_count() 1, 加入购物车后商品数量未正确增加 pytest.mark.order(2) def test_proceed_to_checkout(self, driver): 测试从购物车去结算依赖上一个用例的状态 # 注意这个用例依赖于上一个用例留下的购物车状态。 # 更好的做法是每个用例独立通过setup准备数据。这里为演示流程关联。 from page_objects.cart_page import CartPage cart_page CartPage(driver) # 假设driver当前已经在购物车页面由上一步跳转而来 # 如果不在需要先导航driver.get(cart_url) order_page cart_page.proceed_to_checkout() # 验证是否成功跳转到订单确认页 assert 确认订单 in driver.title, 未成功跳转到订单确认页面 # 可以继续填写收货地址、选择支付方式等需要更多页面对象 # order_page.select_address() # order_page.choose_payment() # ...注意事项测试用例之间应尽可能保持独立避免状态依赖。上面的test_proceed_to_checkout依赖前一个用例的状态这并不是最佳实践。在实际项目中应该通过pytest.fixture在用例开始前准备好一个包含商品的购物车状态。例如可以写一个cart_with_item的fixture通过API或后台操作直接添加一个商品到测试用户的购物车然后UI测试只关注前台的流程验证。5.3 使用Fixture管理复杂前置条件# test_cases/conftest.py (补充) import pytest from utils.api_client import TpshopApiClient # 假设有一个封装好的API客户端 pytest.fixture def cart_with_item(driver, config): 准备一个包含特定商品的购物车环境 api_client TpshopApiClient(config[base_url]) # 1. 通过API登录获取token (避免UI登录的耗时和不稳定) token api_client.login(config[test_user][username], config[test_user][password]) # 2. 通过API将指定商品加入购物车 test_goods_id 123 # 预设的测试商品ID api_client.add_to_cart(token, test_goods_id, quantity1) # 3. 让浏览器携带登录态如Cookie访问购物车页面 driver.delete_all_cookies() for cookie in api_client.get_ui_cookies(token): # 将API登录态转换为浏览器Cookie driver.add_cookie(cookie) driver.refresh() # 刷新页面使Cookie生效 # 现在driver处于已登录且购物车有商品的状态 yield # 测试后清理通过API清空购物车 api_client.clear_cart(token)然后测试用例可以这样写真正做到独立、稳定def test_checkout_from_cart(self, driver, cart_with_item): 测试从已有商品的购物车去结算 # 直接访问购物车页面 driver.get(http://demo.tpshop.cn/index.php?mHomecCartaindex) cart_page CartPage(driver) order_page cart_page.proceed_to_checkout() assert 确认订单 in driver.title6. 执行、报告与持续集成6.1 使用Pytest执行测试在项目根目录下可以通过命令行执行测试# 运行所有测试 pytest # 运行特定目录下的测试 pytest test_cases/ # 运行带有特定标记的测试 pytest -m login # 运行并生成Allure报告所需的原始数据 pytest --alluredir./reports/allure_raw # 多线程运行加速测试执行 pytest -n auto6.2 生成Allure测试报告Allure报告能提供非常直观的测试结果展示包括用例层级、步骤详情、截图、日志等。安装Allure需要先在系统上安装Allure命令行工具。安装Pytest插件pip install allure-pytest执行测试并生成数据pytest --alluredir./reports/allure_raw生成HTML报告allure generate ./reports/allure_raw -o ./reports/allure_html --clean打开报告allure open ./reports/allure_html在测试代码中可以使用allure.step装饰器来标记步骤让报告更清晰import allure class LoginPage(BasePage): allure.step(输入用户名 {username}) def enter_username(self, username): self.input_text(self.USERNAME_INPUT, username) return self allure.step(点击登录按钮) def click_login_button(self): self.click(self.LOGIN_BUTTON)6.3 集成到持续集成CI流水线将UI自动化测试集成到Jenkins、GitLab CI等工具中可以实现代码提交后自动回归测试。核心步骤通常包括拉取代码从版本库获取最新代码。环境准备安装Python依赖 (pip install -r requirements.txt)。浏览器环境在CI服务器上安装浏览器如Chrome和对应的WebDriver可使用webdriver-manager自动处理。执行测试以无头模式 (--headless) 运行测试命令。生成报告生成Allure报告并归档或发布到内部网站。结果通知根据测试结果通过率通过邮件、钉钉、企业微信等通知相关人员。一个简单的GitLab CI.gitlab-ci.yml配置示例stages: - test ui-automation: stage: test image: python:3.9-slim before_script: - apt-get update apt-get install -y wget unzip chromium - pip install -r requirements.txt script: - pytest --alluredir./reports/allure_raw -v after_script: - allure generate ./reports/allure_raw -o ./reports/allure_html --clean artifacts: paths: - ./reports/allure_html expire_in: 1 week only: - main # 仅在main分支提交时触发 - merge_requests7. 常见问题排查与稳定性提升技巧UI自动化测试被称为“脆弱的测试”因为它直接依赖于前端UI。下面是我在TPshop项目实战中遇到的一些典型问题及解决方案。7.1 元素定位失败自动化测试的头号杀手问题现象NoSuchElementException,ElementNotInteractableException等。根本原因页面加载未完成就进行操作。元素定位符XPath, CSS Selector写得不准确或过于复杂页面微调后就失效。元素在iframe或shadow DOM内。元素被弹窗、广告遮挡。解决方案与技巧强制使用显式等待这是最重要的原则。永远不要使用time.sleep()而是用WebDriverWait配合expected_conditions。# 坏味道 time.sleep(5) element driver.find_element(...) # 正确做法 from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC element WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, myElement)) )优化元素定位策略优先级ID Name CSS Selector XPath。避免绝对XPath绝对XPath以/html开头极其脆弱。尽量使用相对XPath或CSS Selector。使用有辨识度的属性优先选择id、name、># 匹配id包含‘submit’按钮的元素 button (By.XPATH, //button[contains(id, submit)]) # 匹配文本包含‘搜索’的按钮 search_btn (By.XPATH, //button[contains(text(), 搜索)])处理iframe在操作iframe内的元素前必须先切换到对应的iframe。# 通过id或name切换 driver.switch_to.frame(iframe_id) # 操作iframe内的元素... # 操作完成后切回主文档 driver.switch_to.default_content()处理弹窗/遮挡尝试点击遮挡物关闭它或者使用JavaScript直接操作目标元素。# 使用JS点击可以绕过一些前端事件拦截 element driver.find_element(...) driver.execute_script(arguments[0].click();, element)7.2 测试用例的独立性与数据污染问题用例A创建的数据影响了用例B的执行。解决每个用例前后清理数据使用Pytest的setup_method/teardown_method或Fixture。使用独立的测试账号为每个测试线程或用例套件准备独立的测试账号和数据。通过API进行数据准备和清理如前文cart_with_itemfixture所示这比UI操作更快更可靠。7.3 提高执行速度使用无头模式在CI环境和调试后期使用--headless。并行执行使用pytest-xdist插件进行多进程并行测试。优化等待时间合理设置全局的隐式等待和每个操作的显式等待超时避免不必要的长时间等待。复用浏览器会话对于登录等耗时操作可以考虑使用scopesession的Fixture只登录一次但要注意用例间的状态隔离。7.4 失败分析与调试失败自动截图在BasePage的异常处理中加入截图功能如前文代码所示。详细日志为每个重要操作记录日志包括操作内容、定位符、成功/失败状态。使用Allure附件将失败时的截图、页面源代码作为附件添加到Allure报告中。import allure pytest.hookimpl(tryfirstTrue, hookwrapperTrue) def pytest_runtest_makereport(item, call): outcome yield rep outcome.get_result() if rep.when call and rep.failed: # 获取driver对象方式取决于你的Fixture设计 driver item.funcargs.get(driver) if driver: allure.attach(driver.get_screenshot_as_png(), name失败截图, attachment_typeallure.attachment_type.PNG) allure.attach(driver.page_source, name页面源码, attachment_typeallure.attachment_type.TEXT)本地调试在调试时关闭无头模式并加入time.sleep()暂停观察浏览器实际行为。通过TPshop这个具体项目的实战拆解我们可以看到UI自动化测试不是一个简单的“录制-回放”游戏而是一个需要精心设计、持续维护的软件工程。从框架选型、工程结构、模式应用到稳定性处理每一个环节都影响着最终的效率和收益。核心思想是将变动的部分UI元素定位与不变的部分业务逻辑验证分离并通过良好的工程实践来保障脚本的可靠性和可维护性。希望这次详细的分享能为你启动自己的UI自动化项目提供一份可靠的“地图”。