当サイトは、アフィリエイト広告を利用しています

【Python】pytestでprintを出力する方法

作成日:2024月08月24日
更新日:2024年08月24日

pytestを使ったテスト実行時にログやメッセージがターミナルに出力できなくて
詰まったので少し調べてみた。

調べるとpytestでログやメッセージ等をターミナルに出力するには

  • print()を使う
  • capsys.readouterr()を使う

の二つの方法がある。 ※printもただ書くだけだと出ない

なぜprintが出力されないのか?

通常、print文はコンソールやターミナルに直接出力を表示するが
pytestがこれをキャプチャすると、出力が一時的に保存され、ターミナルには表示されなくなる。

つまりデフォルトでpytestを実行した場合はprintの内容はターミナルに出力されない。 ※キャプチャされた出力は、テストが成功した場合にはデフォルトで表示されず、pytest によって隠された状態になる

pytestのキャプチャの動作について

キャプチャ(capture)とは、通常の実行中にコンソールやターミナルに出力される内容(標準出力や標準エラー出力)
を一時的に取り込み、保存すること。

pytest では、テスト中に行われる print 文や他の標準出力に対する出力を
自動的にキャプチャして保持するようになっている

printを出力する方法

printを使っての情報を出力は 出力内容がテストの結果に直接関係しない場合や、
単にデバッグ目的で表示したいときに使用する

pytestでprint出力する方法は

  1. テストが失敗する
  2. -s オプションをつけてpytestを実行する
  3. --capture=no オプションをつけてpytestを実行する

の3つがある。
が実際は2,3は動作に違いはないので実質は2パターン。 ※3は割愛

それぞれ動作を確認してみる。

テストが失敗する

下記のコードで確認する

テスト対象

execute_module.py
class ExecuteClass:
def __init__(self,param1):
self.param1 = param1
def callParam1(self):
return self.param1
def main():
instance = ExecuteClass("vscodeでpytest")
print(instance.callParam1())
if __name__ == "__main__": # pragma: no cover
main()

callParam1のテストコードを書く

テストコード

test_execute_module.py
import pytest
from app.execute_module import ExecuteClass,main
@pytest.fixture
def test_setup():
# ExecuteClassのインスタンスを作成
execute_instance = ExecuteClass("vscodeでpytestでキャプチャをする方法")
return execute_instance
def test_callParam1(test_setup, capsys):
execute_instance = test_setup
# callParam1を呼び出し、結果を取得
result = execute_instance.callParam1()
# 結果を出力
print(result)
# 戻り値をアサート(テストを失敗させる)
assert result == "vscodeでpytestでキャプチャをする方法dddd"

敢えてテストを失敗させる

実行結果

実行結果
$ pytest
=========================================================================================== test session starts ============================================================================================
platform win32 -- Python 3.11.1, pytest-8.2.2, pluggy-1.5.0
rootdir: C:\develop\01_TechSamples\Python\Pytest\pytest_vscode
plugins: cov-5.0.0
collected 1 item
tests\test_execute_module.py F [100%]
================================================================================================= FAILURES =================================================================================================
_____________________________________________________________________________________________ test_callParam1 ______________________________________________________________________________________________
test_setup = <app.execute_module.ExecuteClass object at 0x000001C84D623B90>, capsys = <_pytest.capture.CaptureFixture object at 0x000001C84D623850>
def test_callParam1(test_setup, capsys):
execute_instance = test_setup
# callParam1を呼び出し、結果を取得
result = execute_instance.callParam1()
# 結果を出力
print(result)
# 戻り値をアサート
> assert result == "vscodeでpytestでキャプチャをする方法dddd"
E AssertionError: assert 'vscodeでpytestでキャプチャをする方法' == 'vscodeでpytestでキャプチャをする方法dddd'
E
E - vscodeでpytestでキャプチャをする方法dddd
E ? ----
E + vscodeでpytestでキャプチャをする方法
tests\test_execute_module.py:20: AssertionError
------------------------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------------------------
vscodeでpytestでキャプチャをする方法
========================================================================================= short test summary info ==========================================================================================
FAILED tests/test_execute_module.py::test_callParam1 - AssertionError: assert 'vscodeでpytestでキャプチャをする方法' == 'vscodeでpytestでキャプチャをする方法dddd'
============================================================================================ 1 failed in 0.15s =============================================================================================
=========================== short test summary info ===========================
FAILED tests/test_execute_module.py::test_callParam1 - AssertionError: assert...
============================== 1 failed in 0.17s ==============================
Finished running tests!

printが出力される。

ちなみにテスト成功させた場合は下記のようになる

テスト成功
$ pytest
=========================================================================================== test session starts ============================================================================================
platform win32 -- Python 3.11.1, pytest-8.2.2, pluggy-1.5.0
rootdir: C:\develop\01_TechSamples\Python\Pytest\pytest_vscode
plugins: cov-5.0.0
collected 1 item
tests\test_execute_module.py . [100%]
============================================================================================ 1 passed in 0.03s =============================================================================================

printの内容は出力されない。

-s オプションをつけてpytestを実行する

-s オプションをつけると標準出力と標準エラー出力のキャプチャを無効にすることができる
同じソースでテスト成功を実行する

テスト成功
$ pytest -s
=========================================================================================== test session starts ============================================================================================
platform win32 -- Python 3.11.1, pytest-8.2.2, pluggy-1.5.0
rootdir: C:\develop\01_TechSamples\Python\Pytest\pytest_vscode
plugins: cov-5.0.0
collected 1 item
tests\test_execute_module.py vscodeでpytestでキャプチャをする方法
.
============================================================================================ 1 passed in 0.02s =============================================================================================

テストは成功しているがprintの内容が出力される。

キャプチャを出力する方法

pytestで保持しているキャプチャを出力して確認することもできる。
printに対してこちらは出力そのものがテスト対象であり、その内容が正しいかどうかを確認したいときに使う

キャプチャはcapsys.readouterr()関数を使う。

テストコード

テスト対象コードはそのままで、テストコードを変更する

test_execute_module.py
import pytest
from app.execute_module import ExecuteClass,main
@pytest.fixture
def test_setup():
# ExecuteClassのインスタンスを作成
execute_instance = ExecuteClass("vscodeでpytestでキャプチャをする方法")
return execute_instance
def test_callParam1(test_setup, capsys):
execute_instance = test_setup
# callParam1を呼び出し、結果を取得
result = execute_instance.callParam1()
# print文で出力される内容を検証
print(result)
captured = capsys.readouterr() # 標準出力と標準エラー出力をキャプチャ
assert captured.out.strip() == "vscodeでpytestでキャプチャをする方法" # キャプチャされた出力を検証
  • print 文で出力された内容を capsysフィクスチャを使ってキャプチャする
  • キャプチャされた標準出力が期待される文字列と一致するか確認する

assertで比較する場合はcapsysでキャプチャを使う必要がある

キャプチャの範囲について

capsys.readouterr() がキャプチャする範囲は、
capsys.readouterr() が呼び出されるまでに行われた

  • 標準出力 (stdout)
  • 標準エラー出力 (stderr)

の内容すべてになる。

そしてcapsys.readouterr()を呼び出すと、その時点での標準出力と
標準エラー出力が一度クリアされるため、後続の出力は次のcapsys.readouterr()
まで新たにキャプチャされることになる

テストコードを下記のように変更して確認する
※capsys.readouterr()の動作を確認するだけなので検証はしない

test_execute_module.py
import pytest
from app.execute_module import ExecuteClass,main
@pytest.fixture
def test_setup():
# ExecuteClassのインスタンスを作成
execute_instance = ExecuteClass("vscodeでpytestでキャプチャをする方法")
return execute_instance
def test_callParam1(test_setup, capsys):
# execute_instance = test_setup
# # callParam1を呼び出し、結果を取得
# result = execute_instance.callParam1()
# print文で出力される内容を検証
print("1回目")
captured = capsys.readouterr() # 標準出力と標準エラー出力をキャプチャ
print(captured.out) #キャプチャ出力
print("2回目")
captured = capsys.readouterr() # 標準出力と標準エラー出力をキャプチャ
print(captured.out) #キャプチャ出力
# assert captured.out.strip() == "vscodeでpytestでキャプチャをする方法" # キャプチャされた出力を検証

確認に不要な部分はコメントアウトする

実行結果

実行結果
$ pytest -s
=========================================================================================== test session starts ============================================================================================
platform win32 -- Python 3.11.1, pytest-8.2.2, pluggy-1.5.0
rootdir: C:\develop\01_TechSamples\Python\Pytest\pytest_vscode
plugins: cov-5.0.0
collected 1 item
tests\test_execute_module.py 1回目
2回目
.
============================================================================================ 1 passed in 0.04s =============================================================================================

capsys.readouterr()を実行したタイミングで一度クリアされているため
重複して出力はされない。

※キャプチャをprint出力するので-sオプション付きで実行する必要がある。

vscodeで実行する場合

ターミナルでコマンドではなく、VSCode上で実行する場合は
.vscode/setting.jsonを下記のように編集して-sオプション付きで実行するよう設定する。

.vscode/setting.json
{
"python.testing.pytestArgs": [
"-s"
],
}

vscodeでpytestを使う方法については下記でまとめています

まとめ

pytestでターミナルに出力する方法と
その用途がわかったので今後はうまく使い分けていきたい。

関連記事

新着記事

タグ別一覧
top