ZennのScrapsと同じような感覚の記事。間違っている可能性は十分にあります。
今回の記事ではpytest
について自分が調べたことをまとめます。
環境
- Python
- 3.7.9
- pytest
- 7.4.3
- pytest-check
- 2.2.2
Pytestについて
処理順番
pytest
ではヒットした順番で順次テストするのではなく、collection
というテスト対象のメソッドを集めた過程を経てテストを実行します。この実行前のcollection
で先頭にTest
が付いているクラス、test_
がついているメソッドを探しています。感覚的には、200テストを探すのに1秒くらいかかるので、テストケースが増えれば増えるほど起動までに時間がかかります。
--last-failed
というオプションを付けて実行すると、前回のセッションで失敗したテストだけを実行してくれます。しかし地味にcollection
に時間がかかるので、失敗したテストが複数ファイルに跨っていない限りは、失敗したファイルだけで実行したほうが早く済みます。このオプションを付与しているときは、collection
対象を減らすというコントリビュートチャンスかも。
--continue-on-collection-errors
というオプションをつけると、通常はcollection
処理中に一部テストで構文エラーがあった時にはテストを実行しませんが、付与すると構文エラーがあっても他のテストを実行してくれます。基本的にはIDEやプラグインでしか使わないオプションだと思います。
テストレポートについて
メインのテストレポートについては、hook
機能を使用すると書き換えられます。
@pytest.hookimpl(hookwrapper=True, trylast=True) def pytest_runtest_makereport(item, call): pass
使い方は別のライブラリであるpytest-check
を見るのがいいかも。
厄介なのがshort test summary info
という箇所については、一苦労が必要です。次の処理箇所がpytest
のshort test summary info
のメッセージを作成している箇所です。メインのエラーメッセージをstr
で渡すこともできますが、その場合はAttributeError
の処理に入ってしまって値が取得できません。
try: # Type ignored intentionally -- possible AttributeError expected. msg = rep.longrepr.reprcrash.message # type: ignore[union-attr] except AttributeError: pass
- short test summary info の
- XXX
の部分
そのため、pytest
に合わせて次のように値を渡す必要がありました。
# ASIS try: raise AssertionError(report.longrepr) except AssertionError: excinfo = ExceptionInfo.from_current() call.excinfo = excinfo
# TOBE from _pytest.reports import ExceptionChainRepr from _pytest._code.code import ExceptionRepr, ReprFileLocation try: raise AssertionError(report.longrepr) except AssertionError as e: excinfo = ExceptionInfo.from_current() reprcrash = ReprFileLocation(item.nodeid, 0, str(e)) reprtraceback = ExceptionRepr(reprcrash, excinfo) chain_repr = ExceptionChainRepr([(reprtraceback, reprcrash, str(e))]) report.longrepr = chain_repr call.excinfo = excinfo
もうちょっと頭のいいやり方があったかもしれないのですが、上のようにしてlogrepr
をstr
ではなくExceptionChainRepr
で渡せばshort test summary info
に値を渡せました。
その件はこちらのPull Requestに入れています。
オプションについて
とりあえず実行時につけているオプション。このセクションには中身は無いです。
# -p no:warnings はPython側の機能です addopts = ["-p no:warnings", "-p no:logging", "--last-failed", "-s"]
もっと便利になりそうなオプションがあったら追加します。
量が多くて読み切れていないです。
Pytest-Checkについて
Python
でAssertion Roulette
にならないように回避するライブラリ。
JavaでのSoftAssertions
と同じような処理をします。
こちらの紹介記事に関しては、PullRequestがmergeされたら記載する予定です。
ソースコード
なし
終わりに
正直。pytest-check
へのPullRequestを作成したときに色々と調べたメモです。今後もPytest関連のライブラリにコントリビュートするかは置いておいて、一瞬だけ使用する知識としておくのももったいないのでScrapという形で記事化しました。