RPA自动化测试集成实践:用pytest插件提升测试稳定性
2026/6/25 19:20:18 网站建设 项目流程

1. 项目概述:当RPA遇上pytest-surge-sh

最近在折腾一个自动化测试项目,核心是把RPA(机器人流程自动化)的流程执行能力,和基于pytest的自动化测试框架做深度集成。听起来有点绕?简单说,就是让那些原本需要人工点点点、填表格的重复性业务流程,不仅能自动跑起来,还能像我们写单元测试一样,被一套严谨的测试框架所管理和验证。而我这次选择的测试框架核心,是一个叫pytest-surge-sh的插件。

你可能会问,测试框架那么多,为什么是pytest-surge-sh?这得从实际痛点说起。很多RPA流程,特别是涉及Web页面操作、桌面应用交互的,其运行环境并不“纯净”。网络波动、第三方服务响应慢、测试数据被污染,都会导致自动化脚本时好时坏,产生大量“假阳性”或“假阴性”的测试结果,俗称“flakey tests”。pytest-surge-sh这个插件,名字里的“surge”就暗示了它的能力:应对突发流量、不稳定场景。它提供了一套机制,比如重试、并发控制、资源隔离等,专门用来增强测试的稳定性和可靠性。这对于将RPA流程转化为可信赖的自动化测试用例,简直是天作之合。

这个项目适合谁呢?首先是已经用Python开发RPA脚本的工程师,你可能在用seleniumpyautoguiplaywright,或者国内的影刀、来也等平台的SDK。其次是测试开发工程师,希望将业务验收测试(尤其是需要模拟真实用户操作的场景)更稳定地集成到CI/CD流水线中。最后,任何被不稳定自动化测试所困扰的团队,都可以从这个集成思路中获得启发。接下来,我会详细拆解整个集成的设计思路、关键技术细节、实操步骤以及我踩过的那些坑。

2. 整体架构与核心设计思路

2.1 为什么是“RPA + 测试框架”的范式

传统的RPA开发,脚本写好了,设置个定时任务或者手动触发,跑完拉倒。日志可能也有,但断言(Assertion)和结果报告往往很弱,更像一个自动化工具而非测试工具。而传统的UI自动化测试(如用pytest+selenium),虽然测试框架强大,但编写模拟复杂业务流程(比如涉及多个系统、需要处理Excel/邮件/桌面弹窗)的用例时,代码会变得非常臃肿且难以维护。

将两者结合,核心思路是“关注点分离”

  1. RPA脚本(Actor):专注于“怎么做”。它封装了所有底层的操作细节:如何登录系统、如何定位元素、如何读取表格、如何调用API。它的目标是可靠地执行单个或多个操作步骤。
  2. 测试框架(Orchestrator & Validator):专注于“做什么”和“检查什么”。它来调度RPA脚本(或其中的关键步骤),定义测试用例的逻辑流(例如,先执行脚本A,再验证数据库B),并提供强大的断言、夹具(fixture)、参数化、报告和稳定性增强机制。

pytest-surge-sh在这里扮演了“稳定性增强器”和“资源协调者”的角色。通过它,我们可以方便地为这些容易受环境影响的RPA测试用例添加重试策略、设置超时、管理测试会话级别的资源。

2.2 技术栈选型与集成模式

核心技术栈:

  • Python: 毋庸置疑,既是RPA脚本的主流语言,也是pytest的母语。生态丰富,胶水能力一流。
  • pytest: 作为测试框架本体,提供用例发现、夹具、参数化、钩子等核心能力。
  • pytest-surge-sh: 关键插件,用于提升测试稳定性。我们需要深入理解其提供的装饰器、命令行参数和配置项。
  • RPA库/工具: 根据实际业务选择。例如:
    • Web自动化:selenium,playwright,puppeteer(通过pyppeteer)
    • 桌面自动化:pyautogui,pywinauto
    • 企业级RPA平台: 影刀RPA(通过其Python SDK)、来也UiBot等提供的API。
  • 其他辅助:pytest-html用于生成美观报告,pytest-xdist用于并行测试(需注意与surge-sh的并发控制可能产生的冲突),allure-pytest用于生成更强大的测试报告。

集成模式设计:我采用了“封装与调用”模式,而不是“混合编写”。

  1. 独立RPA模块: 将可复用的业务流程操作,封装成独立的Python函数或类方法。例如,login_to_crm(username, password),export_report(date),process_excel_file(file_path)
  2. pytest测试用例: 测试用例文件里,不直接出现find_element_by_id这类底层代码。而是导入上述RPA模块,调用这些函数。
  3. pytest-surge-sh装饰器应用: 在测试类或测试函数上,使用@pytest.mark.flaky(如果surge-sh提供了类似功能) 或通过pytest.ini全局配置重试逻辑,来装饰那些已知不稳定的、由RPA操作构成的测试点。

这种模式的好处是清晰、可维护。RPA脚本开发者可以专注于优化操作逻辑;测试开发者可以专注于设计测试场景和数据。当底层应用界面变化时,通常只需要修改对应的RPA模块,测试用例本身可能无需改动。

3. 环境搭建与核心配置详解

3.1 Python与pytest基础环境

首先确保有一个干净的Python环境(推荐3.8及以上)。使用虚拟环境是必须的,它能避免包冲突。

# 创建并激活虚拟环境 python -m venv venv_rpa_test # Windows: venv_rpa_test\Scripts\activate # Linux/Mac: source venv_rpa_test/bin/activate # 安装核心框架 pip install pytest # 安装 pytest-surge-sh,注意它可能不在PyPI主流仓库,可能需要从GitHub或私有仓库安装 # 例如: pip install pytest-surge-sh # 如果可用 # 或者: pip install git+https://github.com/someorg/pytest-surge-sh.git # 由于“pytest-surge-sh”是一个示例名,这里假设其安装方式。实际中可能是“pytest-rerunfailures”的增强版或内部插件。 # 本文以“pytest-rerunfailures”作为功能类似的可公开访问插件进行演示,它提供了重试机制。 pip install pytest-rerunfailures pip install pytest-html # 用于生成报告

注意pytest-surge-sh作为一个示例插件名,其真实安装源需根据实际情况确定。在找不到的情况下,我们可以用pytest-rerunfailurespytest-timeout等插件组合来实现“稳定性增强”的核心需求。下文将基于这种组合模式进行讲解,其原理是相通的。

3.2 模拟pytest-surge-sh功能的配置

由于pytest-surge-sh的具体API未知,我将创建一个模拟其部分功能的conftest.pypytest.ini配置,来实现重试、超时和资源记录。这实际上是一种“自己动手”实现核心思想的方案,更具普适性。

pytest.ini配置文件:

[pytest] # 指定测试文件路径和命名规则 testpaths = tests python_files = test_*.py python_classes = Test* python_functions = test_* # 模拟 surge-sh 的全局重试配置:对所有失败用例重试2次,每次间隔1秒 addopts = --reruns 2 --reruns-delay 1 --html=report.html --self-contained-html # 定义自定义标记,用于分类那些特别不稳定的RPA测试 markers = rpa_web: 标记涉及Web自动化的RPA测试 rpa_desktop: 标记涉及桌面自动化的RPA测试 flaky: 标记不稳定的测试(可通过此标记选择性地运行更多重试)

conftest.py文件(项目根目录下):这个文件是pytest的本地插件,我们可以在这里实现夹具和自定义钩子,模拟资源管理。

import pytest import time import logging from selenium import webdriver # 示例,假设主要RPA操作是Web from some_rpa_lib import DesktopController # 示例,假设的桌面自动化库 logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # ---- 模拟 surge-sh 的“会话级资源管理”夹具 ---- @pytest.fixture(scope="session") def shared_web_driver(): """ 模拟 surge-sh 可能提供的“稳定、可重用的浏览器会话”。 会话级别,所有测试共用同一个driver,提高速度。 注意:需要处理测试间状态清理问题。 """ logger.info("初始化共享Web Driver(会话开始)") # 这里以Chrome为例,实际请根据需求配置options options = webdriver.ChromeOptions() options.add_argument("--headless") # 无头模式,适合CI环境 options.add_argument("--no-sandbox") options.add_argument("--disable-dev-shm-usage") driver = webdriver.Chrome(options=options) driver.implicitly_wait(10) # 设置隐式等待 yield driver # 测试会话结束后清理 logger.info("清理共享Web Driver(会话结束)") driver.quit() @pytest.fixture(scope="function") # 每个函数(测试用例)一个,更隔离 def clean_web_driver(): """ 函数级别的driver,每个测试完全独立,避免状态污染,但启动开销大。 模拟 surge-sh 可能提供的“隔离测试环境”。 """ logger.info("为测试函数创建新的Web Driver") options = webdriver.ChromeOptions() options.add_argument("--headless") driver = webdriver.Chrome(options=options) driver.implicitly_wait(10) yield driver logger.info("清理测试函数的Web Driver") driver.quit() # ---- 模拟 surge-sh 的“操作重试”装饰器(底层实现) ---- def retry_rpa_operation(max_attempts=3, delay=2, exceptions=(Exception,)): """ 一个自定义装饰器,用于装饰那些不稳定的RPA操作函数。 这不是 pytest 的 mark,而是直接装饰业务函数。 """ def decorator(func): def wrapper(*args, **kwargs): last_exception = None for attempt in range(1, max_attempts + 1): try: logger.info(f"尝试执行 {func.__name__},第 {attempt} 次") return func(*args, **kwargs) except exceptions as e: last_exception = e logger.warning(f"{func.__name__} 第 {attempt} 次尝试失败: {e}") if attempt < max_attempts: time.sleep(delay) # 所有尝试都失败 logger.error(f"{func.__name__} 所有 {max_attempts} 次尝试均失败") raise last_exception return wrapper return decorator # ---- 模拟 surge-sh 的“测试前置后置”钩子,用于记录资源 surge ---- @pytest.hookimpl(tryfirst=True) def pytest_runtest_setup(item): """测试开始前记录""" logger.info(f"[Surge-Sh Log] 开始测试: {item.name}") @pytest.hookimpl(tryfirst=True) def pytest_runtest_teardown(item, nextitem): """测试结束后记录""" logger.info(f"[Surge-Sh Log] 结束测试: {item.name}")

这个conftest.py实现了几个关键概念:

  1. 会话级夹具 (shared_web_driver):模拟surge-sh可能提供的“稳定会话池”,减少浏览器启动开销。
  2. 函数级夹具 (clean_web_driver):提供完全隔离的环境,适合需要干净状态的测试。
  3. 自定义重试装饰器 (retry_rpa_operation):针对业务函数而非测试用例的重试。有时,我们只希望重试一个登录操作,而不是整个测试用例。这提供了更细粒度的控制。
  4. 自定义钩子:在测试开始和结束时打日志,模拟监控“测试浪涌”的行为。

4. RPA操作模块的封装与测试用例编写

4.1 封装可测试的RPA操作

创建一个rpa_operations.py文件,将业务流程封装成函数,并融入稳定性设计。

# rpa_operations.py import logging from typing import Optional from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 导入我们在 conftest 中定义的重试装饰器(实际项目中需放在公共工具模块) from .conftest import retry_rpa_operation logger = logging.getLogger(__name__) class RPAWebOperations: def __init__(self, driver): self.driver = driver self.wait = WebDriverWait(self.driver, 15) # 显式等待 @retry_rpa_operation(max_attempts=3, delay=3, exceptions=(TimeoutError,)) def login_to_portal(self, url: str, username: str, password: str): """ 登录门户网站。这是一个典型的不稳定操作(网络、元素加载)。 使用自定义重试装饰器,仅对登录逻辑本身进行重试。 """ logger.info(f"尝试登录: {url}") self.driver.get(url) # 使用显式等待提高稳定性 username_input = self.wait.until( EC.presence_of_element_located((By.ID, "username")) ) password_input = self.driver.find_element(By.ID, "password") submit_btn = self.driver.find_element(By.TAG_NAME, "button") username_input.send_keys(username) password_input.send_keys(password) submit_btn.click() # 验证登录是否成功,可以检查某个登录后出现的元素 try: self.wait.until( EC.presence_of_element_located((By.ID, "userDashboard")) ) logger.info("登录成功") except TimeoutError: logger.error("登录后未找到预期元素,可能登录失败") raise AssertionError("登录验证失败") def extract_data_from_grid(self, grid_id: str) -> list: """ 从数据表格中提取数据。相对稳定,但可能受数据加载影响。 这里没有用重试装饰器,因为上层测试用例可以用 pytest 的重试。 """ # ... 具体的表格数据提取逻辑 ... data = [] # 示例:找到所有行 rows = self.wait.until( EC.presence_of_all_elements_located((By.CSS_SELECTOR, f"#{grid_id} tr")) ) for row in rows[1:]: # 跳过表头 cols = row.find_elements(By.TAG_NAME, "td") data.append([col.text for col in cols]) return data @retry_rpa_operation(max_attempts=2, delay=1) def click_unstable_button(self, button_text: str): """ 点击一个可能因为动画、弹窗等原因而不稳定的按钮。 专门为此操作设置重试。 """ # 一种更稳健的点击方式:等待元素可点击 button = self.wait.until( EC.element_to_be_clickable((By.XPATH, f"//button[contains(text(), '{button_text}')]")) ) button.click() # 点击后等待一个短暂的UI稳定期 time.sleep(0.5)

关键点:

  • 显式等待优于隐式等待和time.sleepWebDriverWait配合expected_conditions是处理元素加载异步问题的标准做法,能显著减少不必要的等待和超时。
  • 重试策略分层:在conftest.py中我们用pytest-rerunfailures测试用例级重试。在这里,我们用自定义装饰器做业务操作级重试。两者可以结合使用。例如,一个测试用例包含3个RPA操作,其中登录不稳定,我们可以只为login_to_portal函数添加操作级重试。如果整个测试用例因为环境问题失败,则再由用例级重试兜底。
  • 日志记录:在关键步骤添加日志,便于在测试失败时快速定位问题阶段。

4.2 编写pytest测试用例

创建tests/test_rpa_workflow.py文件。

# tests/test_rpa_workflow.py import pytest import logging from rpa_operations import RPAWebOperations logger = logging.getLogger(__name__) # 使用自定义标记分类 @pytest.mark.rpa_web class TestCRMWorkflow: """测试CRM系统中的核心RPA流程""" # 测试用例1:使用共享driver,测试登录和数据提取 def test_login_and_export_summary(self, shared_web_driver): """ 用例:登录CRM并导出当日摘要。 使用了会话级的 shared_web_driver,测试间会共享浏览器状态。 适合流程连贯、需要保持登录状态的测试序列。 """ rpa = RPAWebOperations(shared_web_driver) # 操作1:登录 (该函数自带操作级重试) rpa.login_to_portal("https://demo-crm.example.com", "test_user", "pass123") # 断言1:验证登录后页面标题 assert "Dashboard" in shared_web_driver.title # 操作2:导航到报告页面(假设这是一个相对稳定的操作) shared_web_driver.find_element_by_link_text("每日报告").click() # 操作3:提取数据 report_data = rpa.extract_data_from_grid("dailyReportGrid") # 断言2:验证数据非空且包含关键列 assert len(report_data) > 0 # 这里可以加入更复杂的数据断言,比如检查特定单元格的值 assert any("销售额" in str(row) for row in report_data[0]) logger.info("登录与数据导出测试通过") # 测试用例2:使用干净的driver,测试独立功能 @pytest.mark.flaky(reruns=3, reruns_delay=2) # 使用pytest-rerunfailures的标记,针对此用例额外重试 def test_submit_contact_form(self, clean_web_driver): """ 用例:提交联系表单。 使用函数级的 clean_web_driver,确保每次测试都是全新的会话。 此用例标记为 flaky,因为它依赖的外部验证码服务可能不稳定。 """ rpa = RPAWebOperations(clean_web_driver) clean_web_driver.get("https://demo-crm.example.com/contact") # 填写表单操作... # 假设有一个不稳定的提交按钮 rpa.click_unstable_button("提交") # 验证提交成功提示 success_msg = clean_web_driver.find_element_by_class_name("alert-success") assert "提交成功" in success_msg.text logger.info("联系表单提交测试通过") # 参数化测试:测试不同用户角色的登录 @pytest.mark.parametrize("username, password, expected_role", [ ("admin", "admin123", "管理员"), ("sales", "sales123", "销售员"), ("viewer", "view123", "查看者"), ]) def test_login_with_different_roles(self, clean_web_driver, username, password, expected_role): """ 参数化测试示例:验证不同角色登录后的权限/界面差异。 每个参数组合都会生成一个独立的测试实例。 """ rpa = RPAWebOperations(clean_web_driver) rpa.login_to_portal("https://demo-crm.example.com", username, password) # 假设角色信息显示在用户菜单中 role_element = clean_web_driver.find_element_by_id("userRole") actual_role = role_element.text assert actual_role == expected_role, f"角色验证失败,期望{expected_role},实际{actual_role}"

设计要点:

  • 夹具选择策略shared_web_driver用于需要保持状态的序列化测试,速度快但需注意状态清理。clean_web_driver用于完全独立的测试,更稳定但慢。根据测试需求混合使用。
  • 标记(Mark)的使用:用@pytest.mark.rpa_web标记整个类,方便用pytest -m rpa_web只运行这类测试。用@pytest.mark.flaky标记特别不稳定的单个用例,并为其设置更宽松的重试参数。
  • 参数化测试@pytest.mark.parametrize是数据驱动测试的利器,能极大减少重复代码。非常适合测试同一流程在不同输入数据下的表现。
  • 断言(Assert):断言是测试的灵魂。除了简单的assert语句,可以结合pytest-assume插件(需安装)进行“软断言”,即一个用例中多个断言失败时仍会执行所有断言,最后再汇总报告。

5. 执行、报告与稳定性增强实战

5.1 执行测试与生成报告

在项目根目录下执行测试:

# 运行所有测试 pytest # 只运行标记为 rpa_web 的测试 pytest -m rpa_web # 运行测试并输出详细日志 pytest -v # 如果某个测试文件经常失败,可以单独运行并设置更多重试 pytest tests/test_rpa_workflow.py::TestCRMWorkflow::test_submit_contact_form --reruns 5 --reruns-delay 3 -v

执行后,pytest-html插件会根据pytest.ini的配置,在项目根目录生成report.html文件。用浏览器打开这个文件,可以看到清晰的测试结果汇总、通过/失败/跳过/重试的统计,以及每个失败用例的详细错误信息和日志输出。这对于在CI/CD流水线中查看结果非常方便。

5.2 模拟pytest-surge-sh的高级特性:并发控制与资源隔离

一个真正的“Surge”测试框架可能会处理并发执行。我们可以用pytest-xdist插件来实现并行测试,但需要小心RPA测试的并发冲突(例如,多个测试同时操作同一个浏览器实例或系统资源)。

方案:利用pytest-xdist和夹具作用域控制

  1. 安装pip install pytest-xdist
  2. 修改conftest.py中的夹具:确保共享资源(如shared_web_driver)的作用域是"session",并且是线程安全的。对于WebDriver,通常每个线程/进程需要独立的实例,所以shared_web_driver在并行模式下可能不适用。
  3. 为并行测试设计夹具
    # 在 conftest.py 中增加 @pytest.fixture(scope="function") def parallel_safe_driver(request): """为并行测试准备的driver,每个测试函数独立,通过worker_id区分日志等""" worker_id = getattr(request.config, "workerinput", {}).get("workerid", "master") logger.info(f"[Worker-{worker_id}] 创建新的Web Driver") options = webdriver.ChromeOptions() options.add_argument("--headless") # 可以为不同worker设置不同的用户数据目录,实现更彻底的隔离(如果需要) # options.add_argument(f"--user-data-dir=/tmp/chrome_profile_{worker_id}") driver = webdriver.Chrome(options=options) driver.worker_id = worker_id # 打个标记 yield driver logger.info(f"[Worker-{worker_id}] 退出Web Driver") driver.quit()
  4. 执行并行测试
    # 使用2个worker并行运行测试 pytest -n 2 # 使用auto自动检测CPU核心数 pytest -n auto

    重要警告:并行运行UI自动化测试极具挑战性。确保你的测试用例之间没有资源依赖(不操作同一份文件、同一数据库记录、同一用户会话)。最好为每个并行测试准备独立的测试账号和数据。pytest-surge-sh如果原生支持并发,可能会提供更优雅的会话管理和资源池方案。

5.3 稳定性增强的“组合拳”总结

通过上述实践,我们实际上构建了一套自己的“pytest-surge-sh”增强方案:

  1. 重试机制(Retry)
    • 用例级:通过pytest-rerunfailures--reruns参数或@pytest.mark.flaky标记。
    • 操作级:通过自定义的@retry_rpa_operation装饰器,对关键的不稳定操作进行精准重试。
  2. 超时控制(Timeout):虽然没有在例子中展示,但可以安装pytest-timeout插件,为每个测试用例设置全局或单独的超时时间,防止某个用例卡死整个测试套件。
    pip install pytest-timeout
    pytest.ini中配置:addopts = --timeout=300(每个用例最多300秒)
  3. 等待策略(Wait Strategy):在RPA操作中全面使用显式等待WebDriverWait),摒弃静态sleep,这是提高稳定性的最有效手段之一。
  4. 资源隔离(Isolation)
    • 通过夹具的scope参数(function,class,module,session)控制资源生命周期。
    • 对于并行测试,使用函数级夹具或进程级隔离,避免冲突。
  5. 日志与监控(Logging & Monitoring):完善的日志记录,配合pytest的钩子函数,可以清晰地追踪每个测试步骤和资源使用情况,快速定位不稳定根源。

6. 常见问题、排查技巧与避坑指南

在实际集成过程中,我遇到了不少坑,这里总结一下:

6.1 RPA操作本身的不稳定性

问题现象:元素找不到、点击无效、页面加载超时。排查与解决

  1. 优先使用显式等待:99%的“元素找不到”问题可以通过合适的显式等待解决。不要用time.sleep(10)
  2. 使用更稳健的定位器:优先使用idname。如果使用XPath,尽量避免绝对路径和依赖页面结构的复杂表达式。CSS选择器通常比复杂XPath更高效。
  3. 操作前等待元素可交互:对于点击,使用EC.element_to_be_clickable。对于输入,确保元素是visibleenabled
  4. 处理弹窗和iframe:在操作前,检查是否有意外的弹窗(alert/confirm)阻塞。如果元素在iframe内,必须先用driver.switch_to.frame()切换进去。
  5. 启用重试:对核心的、确实因外部原因不稳定的操作(如第三方登录、文件上传),应用操作级重试装饰器。

6.2 测试用例间的状态污染

问题现象:测试A通过了,测试B却失败了,单独跑B又能通过。排查与解决

  1. 使用函数级 (scope=’function’) 夹具:为每个测试提供全新的浏览器实例或RPA会话。这是最彻底的方案,但会牺牲执行速度。
  2. 认真清理共享状态:如果使用会话级夹具,必须在每个测试开始前结束后清理状态。可以在conftest.py中创建一个autouse=True的夹具。
    @pytest.fixture(autouse=True) def cleanup_shared_state(shared_web_driver): yield # 每个测试结束后执行清理 # 例如:清除cookies,回到首页,关闭非必要标签页等 shared_web_driver.delete_all_cookies() shared_web_driver.get("about:blank")
  3. 设计独立的数据:确保每个测试用例使用唯一标识的测试数据(如唯一的用户名、订单号)。

6.3 并行执行时的冲突

问题现象:并行运行时出现随机失败,日志混乱。排查与解决

  1. 绝对隔离:确保并行测试使用的资源(文件、数据库记录、用户账号)完全没有交集。使用参数化或动态生成唯一标识。
  2. 使用独立的用户目录或配置文件:对于浏览器自动化,通过ChromeOptions的--user-data-dir为每个worker指定独立路径。
  3. 控制并行度:不要一下子开太多worker。UI测试通常比较耗资源,-n 2-n 3可能比-n auto更稳定。
  4. 日志区分:像之前例子一样,在日志中输出worker_id,方便追踪是哪个进程出的问题。

6.4 报告与调试信息不足

问题现象:测试失败了,但报告里只有简单的AssertionError,不知道具体哪一步出了问题。排查与解决

  1. 启用pytest-html并包含截图:修改conftest.py,在测试失败时自动截图并附加到HTML报告中。
    @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(item, call): outcome = yield report = outcome.get_result() if report.when == "call" and report.failed: # 假设测试用例使用了名为‘driver’的夹具 driver_fixture = item.funcargs.get('driver') or item.funcargs.get('shared_web_driver') or item.funcargs.get('clean_web_driver') if driver_fixture and hasattr(driver_fixture, 'save_screenshot'): screenshot_path = f"./screenshots/failure_{item.name}_{report.when}.png" driver_fixture.save_screenshot(screenshot_path) # 将截图路径添加到报告extra中,pytest-html会显示 if hasattr(report, 'extra'): report.extra.append(pytest_html.extras.image(screenshot_path))
    (需要安装pytest-html并正确导入pytest_html
  2. 增加详细的日志输出:在RPA操作函数的关键步骤(开始、结束、关键判断点)都加上logger.info
  3. 使用pytest -v -s-v输出详细信息,-s禁止捕获输出,让打印语句和日志直接显示在控制台,便于实时调试。

6.5 关于“pytest-surge-sh”的思考

由于这是一个假设的插件,我的实践实际上是分解并实现了其可能的核心价值:通过分层级的重试策略、智能的等待、可控的资源管理和完善的监控,将脆弱的RPA流程转化为稳定可靠的自动化测试资产。无论你是否能找到名为pytest-surge-sh的插件,这套方法论和实现细节都是通用的。真正的“Surge”能力,来自于对不稳定根源的深刻理解和对测试框架的灵活运用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询