如何捕捉 stdout/stderr 輸出

預設 stdout/stderr/stdin 捕捉行為

在測試執行期間,任何發送到 stdoutstderr 的輸出都會被捕捉。如果測試或 setup 方法失敗,其相應的捕捉輸出通常會與失敗回溯一起顯示。(此行為可以通過 --show-capture 命令列選項進行配置)。

此外,stdin 被設定為 “null” 物件,該物件在嘗試從中讀取時將會失敗,因為在運行自動化測試時,很少需要等待互動式輸入。

預設情況下,捕捉是通過攔截對低階檔案描述器的寫入來完成的。這允許捕捉來自簡單 print 語句的輸出以及來自測試啟動的子程序的輸出。

設定捕捉方法或停用捕捉

pytest 可以通過三種方式執行捕捉

  • fd (檔案描述器) 層級捕捉 (預設):所有寫入到作業系統檔案描述器 1 和 2 的內容都將被捕捉。

  • sys 層級捕捉:僅捕捉寫入到 Python 檔案 sys.stdoutsys.stderr 的內容。不執行對檔案描述器的寫入捕捉。

  • tee-sys 捕捉:將會捕捉 Python 寫入到 sys.stdoutsys.stderr 的內容,但是寫入也將傳遞到實際的 sys.stdoutsys.stderr。這允許輸出進行 ‘即時列印’ 並被捕捉以供插件使用,例如 junitxml (pytest 5.4 中的新功能)。

您可以從命令列影響輸出捕捉機制

pytest -s                  # disable all capturing
pytest --capture=sys       # replace sys.stdout/stderr with in-mem files
pytest --capture=fd        # also point filedescriptors 1 and 2 to temp file
pytest --capture=tee-sys   # combines 'sys' and '-s', capturing sys.stdout/stderr
                           # and passing it along to the actual sys.stdout/stderr

使用 print 語句進行偵錯

預設捕捉 stdout/stderr 輸出的一個主要好處是您可以使用 print 語句進行偵錯

# content of test_module.py


def setup_function(function):
    print("setting up", function)


def test_func1():
    assert True


def test_func2():
    assert False

並且運行此模組將準確地顯示失敗函數的輸出並隱藏另一個函數的輸出

$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 2 items

test_module.py .F                                                    [100%]

================================= FAILURES =================================
________________________________ test_func2 ________________________________

    def test_func2():
>       assert False
E       assert False

test_module.py:12: AssertionError
-------------------------- Captured stdout setup ---------------------------
setting up <function test_func2 at 0xdeadbeef0001>
========================= short test summary info ==========================
FAILED test_module.py::test_func2 - assert False
======================= 1 failed, 1 passed in 0.12s ========================

從測試函數存取捕捉的輸出

capsyscapsysbinarycapfdcapfdbinary fixtures 允許存取在測試執行期間建立的 stdout/stderr 輸出。

這是一個執行一些與輸出相關的檢查的範例測試函數

def test_myoutput(capsys):  # or use "capfd" for fd-level
    print("hello")
    sys.stderr.write("world\n")
    captured = capsys.readouterr()
    assert captured.out == "hello\n"
    assert captured.err == "world\n"
    print("next")
    captured = capsys.readouterr()
    assert captured.out == "next\n"

readouterr() 呼叫快照目前為止的輸出 - 並且捕捉將繼續進行。在測試函數完成後,原始流將被還原。以這種方式使用 capsys 可以使您的測試免於擔心設定/重置輸出流,並且還可以與 pytest 自己的每個測試捕捉良好地互動。

readouterr() 的返回值是一個 namedtuple,具有兩個屬性,outerr

如果被測程式碼寫入非文字資料 (bytes),您可以使用 capsysbinary fixture 來捕捉,它會從 readouterr 方法返回 bytes

如果您想在檔案描述器層級進行捕捉,您可以使用 capfd fixture,它提供完全相同的介面,但也允許捕捉來自直接寫入作業系統層級輸出流 (FD1 和 FD2) 的程式庫或子程序的輸出。與 capsysbinary 類似,capfdbinary 可用於在檔案描述器層級捕捉 bytes

若要在測試中暫時停用捕捉,捕捉 fixtures 具有一個 disabled() 方法,可以用作上下文管理器,在 with 區塊內停用捕捉

def test_disabling_capturing(capsys):
    print("this output is captured")
    with capsys.disabled():
        print("output not captured, going directly to sys.stdout")
    print("this output is also captured")