stdout/stderr 出力をキャプチャする方法

デフォルトの stdout/stderr/stdin キャプチャ動作

テスト実行中に stdout および stderr に送信された出力はすべてキャプチャされます。 テストまたはセットアップメソッドが失敗した場合、そのキャプチャされた出力は通常、失敗のトレースバックと共に表示されます (この動作は --show-capture コマンドラインオプションで構成できます) 。

さらに、stdin は「null」オブジェクトに設定されており、自動テストを実行する際にインタラクティブな入力を待つことはほとんどないため、読み取りを試みると失敗します。

デフォルトでは、低レベルのファイルディスクリプタへの書き込みをインターセプトすることでキャプチャが行われます。 これにより、単純な print 文からの出力や、テストによって開始されたサブプロセスからの出力をキャプチャできます。

キャプチャ方法の設定またはキャプチャの無効化

pytest がキャプチャを実行する方法は 3 つあります:

  • 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

デバッグのために print 文を使用する

stdout/stderr 出力のデフォルトキャプチャの主な利点の 1 つは、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 ========================

テスト関数からキャプチャされた出力にアクセスする

capsyscapsysbinarycapfd、および 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 独自のテストごとのキャプチャとも良好に連携します。

readouterr の戻り値は、outerr の 2 つの属性を持つ namedtuple に変更されました。

テスト対象のコードが非テキストデータ (bytes) を書き込む場合、capsysbinary フィクスチャを使用してこれをキャプチャできます。 これは readouterr メソッドから bytes を返します。

ファイルディスクリプタレベルでキャプチャしたい場合は、capfd フィクスチャを使用できます。 これはまったく同じインターフェースを提供しますが、オペレーティングシステムレベルの出力ストリーム (FD1 および FD2) に直接書き込むライブラリやサブプロセスからの出力もキャプチャできます。 capsysbinary と同様に、capfdbinary を使用してファイルディスクリプタレベルで bytes をキャプチャできます。

テスト内で一時的にキャプチャを無効にするには、キャプチャフィクスチャに 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")