簡體   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