当サイトは、アフィリエイト広告を利用しています
pytestを使ったテスト実行時にログやメッセージがターミナルに出力できなくて
詰まったので少し調べてみた。
調べるとpytestでログやメッセージ等をターミナルに出力するには
の二つの方法がある。 ※printもただ書くだけだと出ない
通常、print文はコンソールやターミナルに直接出力を表示するが
pytestがこれをキャプチャすると、出力が一時的に保存され、ターミナルには表示されなくなる。
つまりデフォルトでpytestを実行した場合はprintの内容はターミナルに出力されない。 ※キャプチャされた出力は、テストが成功した場合にはデフォルトで表示されず、pytest によって隠された状態になる
キャプチャ(capture)とは、通常の実行中にコンソールやターミナルに出力される内容(標準出力や標準エラー出力)
を一時的に取り込み、保存すること。
pytest では、テスト中に行われる print 文や他の標準出力に対する出力を
自動的にキャプチャして保持するようになっている
printを使っての情報を出力は
出力内容がテストの結果に直接関係しない場合や、
単にデバッグ目的で表示したいときに使用する
pytestでprint出力する方法は
の3つがある。
が実際は2,3は動作に違いはないので実質は2パターン。
※3は割愛
それぞれ動作を確認してみる。
下記のコードで確認する
class ExecuteClass:def __init__(self,param1):self.param1 = param1def callParam1(self):return self.param1def main():instance = ExecuteClass("vscodeでpytest")print(instance.callParam1())if __name__ == "__main__": # pragma: no covermain()
callParam1のテストコードを書く
import pytestfrom app.execute_module import ExecuteClass,main@pytest.fixturedef test_setup():# ExecuteClassのインスタンスを作成execute_instance = ExecuteClass("vscodeでpytestでキャプチャをする方法")return execute_instancedef 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.0rootdir: C:\develop\01_TechSamples\Python\Pytest\pytest_vscodeplugins: cov-5.0.0collected 1 itemtests\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'EE - vscodeでpytestでキャプチャをする方法ddddE ? ----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.0rootdir: C:\develop\01_TechSamples\Python\Pytest\pytest_vscodeplugins: cov-5.0.0collected 1 itemtests\test_execute_module.py . [100%]============================================================================================ 1 passed in 0.03s =============================================================================================
printの内容は出力されない。
-s オプションをつけると標準出力と標準エラー出力のキャプチャを無効にすることができる
同じソースでテスト成功を実行する
$ pytest -s=========================================================================================== test session starts ============================================================================================platform win32 -- Python 3.11.1, pytest-8.2.2, pluggy-1.5.0rootdir: C:\develop\01_TechSamples\Python\Pytest\pytest_vscodeplugins: cov-5.0.0collected 1 itemtests\test_execute_module.py vscodeでpytestでキャプチャをする方法.============================================================================================ 1 passed in 0.02s =============================================================================================
テストは成功しているがprintの内容が出力される。
pytestで保持しているキャプチャを出力して確認することもできる。
printに対してこちらは出力そのものがテスト対象であり、その内容が正しいかどうかを確認したいときに使う
キャプチャはcapsys.readouterr()関数を使う。
テスト対象コードはそのままで、テストコードを変更する
import pytestfrom app.execute_module import ExecuteClass,main@pytest.fixturedef test_setup():# ExecuteClassのインスタンスを作成execute_instance = ExecuteClass("vscodeでpytestでキャプチャをする方法")return execute_instancedef 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でキャプチャをする方法" # キャプチャされた出力を検証
assertで比較する場合はcapsysでキャプチャを使う必要がある
capsys.readouterr() がキャプチャする範囲は、
capsys.readouterr() が呼び出されるまでに行われた
の内容すべてになる。
そしてcapsys.readouterr()を呼び出すと、その時点での標準出力と
標準エラー出力が一度クリアされるため、後続の出力は次のcapsys.readouterr()
まで新たにキャプチャされることになる
テストコードを下記のように変更して確認する
※capsys.readouterr()の動作を確認するだけなので検証はしない
import pytestfrom app.execute_module import ExecuteClass,main@pytest.fixturedef test_setup():# ExecuteClassのインスタンスを作成execute_instance = ExecuteClass("vscodeでpytestでキャプチャをする方法")return execute_instancedef 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.0rootdir: C:\develop\01_TechSamples\Python\Pytest\pytest_vscodeplugins: cov-5.0.0collected 1 itemtests\test_execute_module.py 1回目2回目.============================================================================================ 1 passed in 0.04s =============================================================================================
capsys.readouterr()を実行したタイミングで一度クリアされているため
重複して出力はされない。
※キャプチャをprint出力するので-sオプション付きで実行する必要がある。
ターミナルでコマンドではなく、VSCode上で実行する場合は
.vscode/setting.jsonを下記のように編集して-sオプション付きで実行するよう設定する。
{"python.testing.pytestArgs": ["-s"],}
vscodeでpytestを使う方法については下記でまとめています
pytestでターミナルに出力する方法と
その用途がわかったので今後はうまく使い分けていきたい。