繁体   English   中英

Pytest 捕获某个测试的stdout

[英]Pytest capture stdout of a certain test

有没有办法只为特定测试获取Captured stdout call而不会使测试失败?

假设我有 10 个测试,外加一个 test_summary。 test_summary 实际上只是打印测试的某种摘要/统计数据,但为了让我获得该输出/打印输出,我目前必须故意使该测试失败。 当然这个 test_summary 最后使用 pytest-ordering 运行。 但是有没有更好的方法可以在不通过测试的情况下获得结果呢? 或者它不应该在测试中,而是在 conftest.py 或其他东西中? 请就最佳实践以及我如何获得此摘要/结果提出建议(基本上是我编写的特定脚本的打印输出)

首先,回答你的确切问题:

有没有办法只为特定测试获取Captured stdout call而不会使测试失败?

您可以添加一个自定义部分,模仿Captured stdout call并在测试成功时打印。 在每个测试中捕获的 output 存储在相关的TestReport object 中,并通过report.capstdout访问。 示例实现:将以下代码添加到项目或测试根目录中的conftest.py中:

import os

def pytest_terminal_summary(terminalreporter, exitstatus, config):
    # on failures, don't add "Captured stdout call" as pytest does that already
    # otherwise, the section "Captured stdout call" will be added twice
    if exitstatus > 0:
        return
    # get all reports
    reports = terminalreporter.getreports('')
    # combine captured stdout of reports for tests named `<smth>::test_summary`
    content = os.linesep.join(
        report.capstdout for report in reports
        if report.capstdout and report.nodeid.endswith("test_summary")
    )
    # add custom section that mimics pytest's one
    if content:
        terminalreporter.ensure_newline()
        terminalreporter.section(
            'Captured stdout call',
            sep='-',
            blue=True,
            bold=True,
        )
        terminalreporter.line(content)

这将添加一个自定义部分Captured stdout call ,该调用将只打印为 ID 以 test_summary 结尾的测试捕获的test_summary (如果您有多个名为test_summary的测试函数,请扩展检查)。 为了区分这两个部分,自定义部分有一个蓝色的 header; 如果您希望它与原始颜色匹配,请通过blue=True arg 删除颜色设置。


现在,解决您的实际问题:

test_summary实际上只是打印测试的某种摘要/统计信息

使用自定义报告测试对我来说很像是一种变通方法; 为什么不在测试中收集数据并在之后添加一个自定义部分来打印该数据? 要收集数据,您可以使用record_property fixture:

def test_foo(record_property):
    # records a key-value pair
    record_property("hello", "world")


def test_bar(record_property):
    record_property("spam", "eggs")

收集和 output 记录的自定义属性,稍微改变上面的 hookimpl。 通过report.user_properties record_property

import os


def pytest_terminal_summary(terminalreporter, exitstatus, config):
    reports = terminalreporter.getreports('')
    content = os.linesep.join(
        f'{key}: {value}' for report in reports
        for key, value in report.user_properties
    )
    if content:
        terminalreporter.ensure_newline()
        terminalreporter.section(
            'My custom summary',
            sep='-',
            blue=True,
            bold=True
        )
        terminalreporter.line(content)

运行上述测试现在产生:

$ pytest test_spam.py 
=============================== test session starts ================================
platform linux -- Python 3.9.0, pytest-6.1.2, py-1.9.0, pluggy-0.13.1
rootdir: /home/oleg.hoefling/projects/private/stackoverflow/so-64812992
plugins: metadata-1.10.0, json-report-1.2.4, cov-2.10.1, forked-1.3.0, xdist-2.1.0
collected 2 items                                                                  

test_spam.py ..                                                              [100%]

-------------------------------- My custom summary ---------------------------------
hello: world
spam: eggs
================================ 2 passed in 0.01s =================================

您可以使用标准的 pytest 终端记者。

def test_a(request):
    reporter = request.config.pluginmanager.getplugin("terminalreporter")
    reporter.write_line("Hello", yellow=True)
    reporter.write_line("World", red=True)

reporter 是我记得的所有 pytest 版本的标准插件。 不幸的是,它没有记录在案,而 API 非常稳定。

你可以在pytest的github上找到TerminalReporter class: https://github.com/pytest-dev/pytest/blob/master/src/_pytest/terminal.py

对您最有用的方法可能是ensure_line()write()flush()和绝对冠军 -- write_line() ,它们可以完成所有工作。

可用的 styles 可以在https://github.com/pytest-dev/pytest/blob/master/src/_pytest/_io/terminalwriter.py找到

_esctable = dict(
    black=30,
    red=31,
    green=32,
    yellow=33,
    blue=34,
    purple=35,
    cyan=36,
    white=37,
    Black=40,
    Red=41,
    Green=42,
    Yellow=43,
    Blue=44,
    Purple=45,
    Cyan=46,
    White=47,
    bold=1,
    light=2,
    blink=5,
    invert=7,
)

小写 styles 表示前景,大写表示背景。

例如,绿色文本上的黄色应打印为

reporter.write_line("Text", yellow=True, Green=True)

我希望这个说明能有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM