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

如何让pytest-stress在pytest-html中按迭代单独展示测试结果?

问题

我需要用pytest-stress按时长运行测试,之前用的是按迭代次数运行的pytest-repeat,并且通过pytest-html生成测试报告。切换到pytest-stress后,所有测试迭代结果都合并在同一行,但pytest-repeat能把每个迭代的测试结果单独分行展示。我希望pytest-stress的每个测试迭代在pytest-html里单独成行,格式类似test_report.py::TestReport::test_fail[1]。

已知pytest-stress重写了会话级别的pytest_runtestloop钩子,我尝试参考pytest-repeat中重写函数级别pytest_generate_tests的逻辑修改了conftest.py,但没成功。现在想知道能不能通过微调conftest.py实现需求,还是必须自定义pytest插件。

示例测试代码

import logging
class TestReport:
    def test_pass(self):
        logging.info("assert(True)")
        assert(True)

    def test_fail(self):
        logging.info("assert(False)")
        assert(False)

已修改的conftest.py代码

def pytest_html_results_table_header(cells):
    cells.insert(2, html.th("Time", class_="sortable time", col="time"))
    cells.pop()


def pytest_html_results_table_row(report, cells):
    cells.insert(2, html.td(datetime.utcnow(), class_="col-time"))
    cells.pop()


@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    report = outcome.get_result()
    setattr(report, "duration_formatter", "%H:%M:%S.%f")

@pytest.hookimpl(tryfirst=True)
def pytest_configure(config):
    if not os.path.exists('results'):
        os.makedirs('results')
    config.option.htmlpath = 'results/results_'+datetime.now().strftime("%Y-%m-%d_T%H-%M-%S")+".html"

#change name based on iteration
def pytest_itemcollected(item):
    cls = item.getparent(pytest.Class)
    iter = 0
    if hasattr(cls.obj, "iteration"):
        iter = int(getattr(cls.obj, "iteration"))
    item._nodeid = item._nodeid + f"[{iter}]"
解决方案

可以通过微调conftest.py实现需求,不需要自定义插件。核心思路是在pytest-stress的迭代循环中,为每个测试实例注入迭代编号,并修改测试报告的节点ID,让pytest-html识别为不同的测试条目。

具体修改步骤如下:

  • 用会话级变量跟踪当前迭代次数
  • 在测试运行前动态修改节点ID,添加迭代编号
  • 确保报告使用修改后的节点ID,让pytest-html将每个迭代视为独立条目

修改后的conftest.py代码:

import os
import datetime
import pytest
from py.xml import html

def pytest_configure(config):
    if not os.path.exists('results'):
        os.makedirs('results')
    config.option.htmlpath = 'results/results_'+datetime.now().strftime("%Y-%m-%d_T%H-%M-%S")+".html"
    # 初始化迭代计数器
    config.stress_iteration = 0

def pytest_html_results_table_header(cells):
    cells.insert(2, html.th("Time", class_="sortable time", col="time"))
    cells.pop()

def pytest_html_results_table_row(report, cells):
    cells.insert(2, html.td(datetime.utcnow(), class_="col-time"))
    cells.pop()

@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_protocol(item, nextitem):
    session = item.session
    # 每次测试运行前递增迭代计数器
    session.config.stress_iteration += 1
    original_nodeid = item.nodeid
    # 为当前测试实例添加迭代编号
    item.nodeid = f"{original_nodeid}[{session.config.stress_iteration}]"
    try:
        yield
    finally:
        # 恢复原始节点ID,避免干扰后续逻辑
        item.nodeid = original_nodeid

@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    report = outcome.get_result()
    setattr(report, "duration_formatter", "%H:%M:%S.%f")
    # 确保报告使用带迭代编号的节点ID
    report.nodeid = item.nodeid

说明:

  • pytest_configure中初始化stress_iteration变量,用于跟踪迭代次数
  • pytest_runtest_protocol在每次测试运行前修改节点ID,执行完成后恢复原始ID,避免影响其他测试流程
  • pytest_runtest_makereport让报告使用修改后的节点ID,这样pytest-html会将每个迭代视为独立测试条目,单独分行展示

修改后,测试迭代结果会以test_report.py::TestReport::test_fail[1]、test_report.py::TestReport::test_fail[2]的形式在报告中单独显示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 20:48:18