You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在pytest/xdist框架中存储全局Test Run ID配置数据的技术咨询

刚好我之前搭建过类似的pytest+xdist+Selenium Grid测试框架,还对接过自定义日志系统,分享下我是怎么解决Test Run ID跨用例共享这个问题的——毕竟xdist是多进程运行,普通全局变量根本没法跨进程传递,得用pytest的钩子和进程间传递机制来实现。

核心解决方案步骤

1. 在Master进程提前创建Test Run ID并传递给所有Worker

xdist的Worker进程是独立的Python解释器,所以必须在Master进程(也就是启动pytest的主进程)里先调用API生成Test Run ID,再把这个ID传递给每个Worker。我们可以用pytest的两个钩子来实现:

# conftest.py
import pytest
import requests

def pytest_configure(config):
    # 只在Master进程执行这个逻辑(Worker进程会有workerinput属性)
    if not hasattr(config, 'workerinput'):
        # 调用你的创建测试运行API,替换成实际的接口地址和参数
        create_run_response = requests.post(
            "http://your-log-system/api/test-runs",
            json={"run_name": "自动化测试运行", "env": "测试环境"}
        )
        create_run_response.raise_for_status()  # 确保API调用成功
        config.test_run_id = create_run_response.json()["test_run_id"]

def pytest_configure_node(node):
    # 把Master进程的Test Run ID传递给每个Worker的config对象
    node.config.test_run_id = node.config.master_config.test_run_id

这样每个Worker进程的request.config里就都能拿到test_run_id了。

2. 封装日志API工具类

为了让测试用例调用日志接口更方便,我封装了一个工具类,把Test Run ID作为初始化参数,后续创建用例、记录日志/截图都直接调用类方法:

# utils/log_client.py
import requests
from typing import Optional

class LogAPIClient:
    def __init__(self, test_run_id: str):
        self.test_run_id = test_run_id
        self.base_api_url = "http://your-log-system/api"

    def create_test_case(self, case_name: str, case_path: str) -> str:
        """在当前测试运行下创建测试用例记录,返回Test Case ID"""
        resp = requests.post(
            f"{self.base_api_url}/test-cases",
            json={
                "test_run_id": self.test_run_id,
                "case_name": case_name,
                "case_path": case_path
            }
        )
        resp.raise_for_status()
        return resp.json()["test_case_id"]

    def log_text(self, test_case_id: str, content: str):
        """给指定测试用例记录文本日志"""
        requests.post(
            f"{self.base_api_url}/test-cases/{test_case_id}/logs/text",
            json={"content": content}
        )

    def log_screenshot(self, test_case_id: str, screenshot_bytes: bytes, filename: str = "screenshot.png"):
        """给指定测试用例上传截图"""
        requests.post(
            f"{self.base_api_url}/test-cases/{test_case_id}/logs/screenshot",
            files={"file": (filename, screenshot_bytes, "image/png")}
        )

3. 用Fixture集成日志工具到测试流程

我写了一个function级别的fixture,在每个测试用例执行前自动创建对应的用例记录,并且把日志客户端和Test Case ID传递给用例:

# conftest.py
from utils.log_client import LogAPIClient
import pytest

@pytest.fixture(scope="function")
def log_tool(request):
    # 从config获取Test Run ID
    test_run_id = request.config.test_run_id
    log_client = LogAPIClient(test_run_id)
    
    # 创建当前测试用例的日志记录
    case_name = request.node.name
    case_path = request.node.nodeid
    test_case_id = log_client.create_test_case(case_name, case_path)
    
    # 把Test Case ID绑定到request对象,方便用例里直接用
    request.test_case_id = test_case_id
    yield log_client
    
    # 用例执行结束后,自动记录执行状态
    status = "PASSED" if request.node.rep_call.passed else "FAILED"
    log_client.log_text(test_case_id, f"测试用例执行完成,状态: {status}")

# 这个钩子用来捕获测试用例的执行结果,供上面的fixture使用
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    rep = outcome.get_result()
    # 把不同阶段的测试结果存到item对象里
    setattr(item, f"rep_{rep.when}", rep)

4. 在测试用例中使用日志工具

现在测试用例里就可以直接调用日志工具来记录内容和截图了,完全不用关心Test Run ID的传递问题:

# tests/test_login.py
def test_user_login(log_tool, selenium_driver):
    # 执行登录操作
    selenium_driver.get("https://your-test-site.com/login")
    selenium_driver.find_element("id", "username").send_keys("test_user")
    selenium_driver.find_element("id", "password").send_keys("123456")
    selenium_driver.find_element("id", "login-btn").click()
    
    # 记录文本日志
    log_tool.log_text(request.test_case_id, "用户登录操作执行完成")
    
    # 截图并上传(直接用Selenium的get_screenshot_as_bytes,不用存本地文件)
    screenshot_data = selenium_driver.get_screenshot_as_bytes()
    log_tool.log_screenshot(request.test_case_id, screenshot_data, "login_success.png")
    
    # 断言登录成功
    assert "欢迎回来" in selenium_driver.page_source

几个关键注意点

  • 避免重复创建Test Run ID:一定要在Master进程里创建,Worker进程只负责接收,不然每个Worker都会生成一个新的Test Run ID,日志就乱了。
  • API异常处理:实际使用时记得给API调用加try-except,比如网络超时、接口报错时可以重试或者记录错误日志,别让API问题打断测试流程。
  • Selenium Grid截图:如果用Grid执行,直接用get_screenshot_as_bytes获取二进制数据传给API就行,不用存本地文件(Worker进程的本地路径在Grid节点上可能访问不到)。

内容的提问来源于stack exchange,提问作者sprad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:17:04