【问题标题】:In py.test is it possible to report arbitrary values generated in the test runs?在 py.test 中是否可以报告测试运行中生成的任意值?
【发布时间】:2025-11-27 19:30:01
【问题描述】:

我知道有用于性能测试和 py.test 分析的插件,但有没有办法生成在测试后报告或以某种方式访问​​的任意值?

想象一下我有一个这样的测试

def test_minimum_learning_rate():
    """Make some fancy stuff and generate a learning performance value"""
    learning_rate = fancy_learning_function().rate
    pytest.report("rate", learning_rate)
    assert learning_rate > 0.5

pytest.report(..) 行是我希望拥有的(但不存在,是吗?)

现在我希望将minimum_learning_rate[rate] 之类的内容与实际测试结果一起写入报告(或者至少在屏幕上)。

真的不错的是 Jenkins 的一些插件,它可以根据这些数据创建一个漂亮的图表。

这有典型的措辞吗?我一直在寻找kpiarbitrary valuesuser defined values,但还没有任何运气..

【问题讨论】:

  • 查看Hypothesis
  • 嗯 - 这只是另一个测试框架,不是吗?我的问题是关于 py.test。无论如何我都会看看,但在快速查看之后,我没有发现太多关于将实际值写入报告的内容..
  • 您可以将它与pytest 一起使用,对Link 的不同输入运行测试,即假设可以根据某些策略为测试生成输入
  • 不太清楚您要如何报告这些值 - 测试代码中的简单 printpytest -s 已经显示数据。但是,请注意 pytest 默认情况下不会在测试之间输出;测试执行完成后可以(并且应该)打印自定义输出(有挂钩)。如果您想要 JUnit 报告中的自定义数据,也有相应的固定装置。
  • 至于在 Jenkins 中绘制数据,pytest 无法处理,必须通过 Jenkins 插件来完成。您可以查看Jenkins JUnit plugin 如何显示测试图表并基于此编写您自己的插件。

标签: python performance report pytest kpi


【解决方案1】:

如果您只想输出一些调试值,print 调用结合 -s 参数就足够了:

def test_spam():
    print('debug')
    assert True

运行pytest -s

collected 1 item                                                                                                                                                                                                  

test_spam.py debug
.

如果您正在寻找更好地集成到pytest 执行流程中的解决方案,请编写自定义挂钩。下面的例子应该会给你一些想法。

每次测试执行后打印自定义行

# conftest.py

def pytest_report_teststatus(report, config):
    if report.when == 'teardown':  # you may e.g. also check the outcome here to filter passed or failed tests only
        rate = getattr(config, '_rate', None)
        if rate is not None:
            terminalreporter = config.pluginmanager.get_plugin('terminalreporter')
            terminalreporter.ensure_newline()
            terminalreporter.write_line(f'test {report.nodeid}, rate: {rate}', red=True, bold=True)

测试:

def report(rate, request):
    request.config._rate = rate

def test_spam(request):
    report(123, request)

def test_eggs(request):
    report(456, request)

输出:

collected 2 items                                                                                                                                                                                                 

test_spam.py .
test test_spam.py::test_spam, rate: 123

test_spam.py .
test test_spam.py::test_eggs, rate: 456
===================================================== 2 passed in 0.01 seconds =====================================================

测试执行后收集数据并打印

# conftest.py

def pytest_configure(config):
    config._rates = dict()

def pytest_terminal_summary(terminalreporter, exitstatus, config):
    terminalreporter.ensure_newline()
    for testid, rate in config._rates.items():
        terminalreporter.write_line(f'test {testid}, rate: {rate}', yellow=True, bold=True)

测试:

def report(rate, request):
    request.config._rates[request.node.nodeid] = rate

def test_spam(request):
    report(123, request)

def test_eggs(request):
    report(456, request)

输出:

collected 2 items                                                                                                                  

test_spam.py ..

test test_spam.py::test_spam, rate: 123
test test_spam.py::test_eggs, rate: 456
===================================================== 2 passed in 0.01 seconds =====================================================

在 JUnit XML 报告中附加数据

使用record_property 夹具:

def test_spam(record_property):
    record_property('rate', 123)

def test_eggs(record_property):
    record_property('rate', 456)

结果报告:

$ pytest --junit-xml=report.xml
...
$ xmllint --format report.xml
<testsuite errors="0" failures="0" name="pytest" skipped="0" tests="2" time="0.056">
  <testcase classname="test_spam" file="test_spam.py" line="12" name="test_spam" time="0.001">
    <properties>
      <property name="rate" value="123"/>
    </properties>
  </testcase>
  <testcase classname="test_spam" file="test_spam.py" line="15" name="test_eggs" time="0.001">
    <properties>
      <property name="rate" value="456"/>
    </properties>
  </testcase>
</testsuite>

【讨论】:

  • 我会在下周检查这个 - 但至少 record_property 听起来非常接近我正在寻找的内容
最近更新 更多