如何擷取 stdout/stderr 輸出¶
預設 stdout/stderr/stdin 擷取行為¶
在測試執行期間,傳送至 stdout
和 stderr
的任何輸出都會被擷取。如果測試或設定方法失敗,其對應的擷取輸出通常會與失敗追蹤一起顯示。(此行為可透過 --show-capture
命令列選項進行設定)。
此外,stdin
會設定為「空值」物件,當嘗試從中讀取時會失敗,因為在執行自動化測試時很少需要等待互動式輸入。
預設情況下,擷取是透過攔截寫入至低階檔案描述詞來完成的。這允許從簡單列印陳述式以及測試啟動的子處理序擷取輸出。
設定擷取方法或停用擷取¶
有下列三種方式讓 pytest
執行擷取
fd
(檔案描述詞)層級擷取(預設):傳送至作業系統檔案描述詞 1 和 2 的所有寫入都會被擷取。sys
層級擷取:只有寫入 Python 檔案sys.stdout
和sys.stderr
的內容會被擷取。不會擷取寫入檔案描述詞的內容。tee-sys
擷取:寫入 Python 檔案sys.stdout
和sys.stderr
的內容會被擷取,但寫入內容也會傳遞至實際的sys.stdout
和sys.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
使用列印陳述式進行除錯¶
預設擷取 stdout/stderr 輸出的主要好處之一是你可以使用列印陳述式進行除錯
# 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 ========================
從測試函式存取擷取的輸出¶
capsys
、capsysbinary
、capfd
和 capfdbinary
固定裝置允許存取測試執行期間建立的 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 自身的每個測試擷取良好互動。
如果你想在檔案描述符層級擷取,你可以使用 capfd
固定裝置,它提供完全相同的介面,但允許從直接寫入作業系統層級輸出串流 (FD1 和 FD2) 的函式庫或子程序擷取輸出。
readouterr
的傳回值已變更為具有兩個屬性的 namedtuple
,out
和 err
。
如果測試中的程式碼寫入非文字資料,你可以使用 capsysbinary
固定裝置擷取,它會從 readouterr
方法傳回 bytes
。
如果測試中的程式碼寫入非文字資料,你可以使用 capfdbinary
固定裝置擷取,它會從 readouterr
方法傳回 bytes
。capfdbinary
固定裝置在檔案描述符層級執行。
若要暫時停用測試中的擷取,capsys
和 capfd
都有一個 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")