Open6
【メモ】テスト駆動Python 第2版
1章:はじめてのpytest
理解
- 単語
- トレースバック:pytestの実行ログのうち、テストが失敗した正確な場所とその周囲のコードを 表示するセクション。
- テストディスカバリ:pytestを実行する際に、実行するテストを検索する部分
- CLIオプション
-
-v, --verbose
でログの詳細表示 -
--tb=no
でトレースバックの表示をオフ
-
- テスト結果見方
- PASSED
- FAILED(テストのエラー)
- SKIPPED
- XFAIL(失敗するはずのテストが想定通りに失敗した)
- XPASS(xfail マーカーが付いたテストの実行が想定に反して成功)
- ERROR(フィクスチャなどテストの結果以外でのエラー)
疑問・確認
- XFAILの使い方としては、システム上で設定したエラーをちゃんと吐き出せているかのテストをする時とか?
2章:テスト関数を書く
理解
- pytestでは任意の式を
assert <式>
で表現できてシンプル。(assertでなくても例外が出されればエラーを出す仕様にはなっている)- unittestだと
assertTrue
やassertEqual
などが必要
- unittestだと
- まれに
assert
が適していない場合があり、その時はpytest.fail()
を使う- 例えば、複雑なアサーションチェックを行う際はアサーションヘルパー関数を定義するが、その中で
pytest.fail()
を使う - https://docs.pytest.org/en/7.1.x/example/simple.html?highlight=assertion helper#writing-well-integrated-assertion-helpers
- 例えば、複雑なアサーションチェックを行う際はアサーションヘルパー関数を定義するが、その中で
- 例外が出されればテストは失敗してしまう。例外が出ることを想定するテストの場合は
pytest.raises()
を使う - Arrange-Act-Assert(準備 - 実行 - 検証)を意識する
- 初期状態/データ整備 - 正しいふるまいか確認したい動作の実行 - 結果
- 一つのクラスに複数のテストをまとめることができる。もちろん継承もできるが、テストにおいてはクラスは特定のものをまとめるためだけに使うのがよい。
- デバッグの際は特定のテストだけ実行して挙動を確認できるのが便利。
疑問・確認
-
pytest.fail()
を使うケースの感覚がふわふわなので、どのようなものがあるか調べておきたい。
3章:pytestのフィクスチャ
理解
- テストのセットアップやティアダウンにはフィクスチャを使う
- fixture関数のyieldより前がセットアップ、yieldより後がティアダウン
-
--setup-show
でフィクスチャのセットアップやティアダウンも含めてログを出せる
- フィクスチャのスコープ
@pytest.fixture(scope="<scope>")
- "function"(default):関数ごとに1回実行
- "class":クラスごとに1回実行
- "module":モジュールごと
- "package":パッケージごと
- "session":pytestコマンド1回で1回実行
-
conftest.py
に記述されたフィクスチャは、明示的にimportしなくても使える- テストディレクトリであればどの階層に配置しても問題ない
- どの階層のフィクスチャが使われているかを確認するには
--fixtures
を使う
- 複数の階層のフィクスチャを組み合わせテストを効率的にする
- フィクスチャのスコープをは動的に決定できる
- フィクスチャのスコープはフィクスチャの定義時に決める必要がある。
- 呼び出し時にスコープをどこに設定するかをparserを使って動的に決めるテクニックみたいなものはある
- 全てのテストに共通したフィクスチャを使う場合
- フィクスチャを引数に渡さなくても
autouse=True
を設定しておけば良い - それほど使用頻度は高くなく、特に理由がなければフィクスチャは明示する
- フィクスチャを引数に渡さなくても
疑問・確認
- フィクスチャのスコープを動的にするのはよく使われているパターンか?結構複雑になりそうだが。
4章:組み込みフィクスチャ
理解
- 一時ディレクトリ
-
tmp_path
:関数スコープ -
tmp_path_factory
:セッションスコープ
-
- CLI呼び出し、テスト
-
capsys
を作う -
with capsys.disable
の中でテストを書くことででテストの出力を表示できる
-
- monkeypatch
- アプリケーションコードの実行環境をいじれる、一部のテストだけDBを一時ディレクトリにリダイレクトするなど可能
- 公式の環境変数やConfigの例がわかりやすい
疑問・確認
- monkeypatchの公式のAPIの例だとAPIの投げる先をモックしているが、DjangoとかFastAPIとかはその辺便利なものが充実してるし、そっち使えば良さそう
5章:パラメータ化
理解
- 同じようなコードのテストを繰り返す場合パラメータ化する
- それぞれのテストでフルで書くと冗長
- 一つにまとめるとテストが何で失敗したかわかりづらい
- パラメータ化の方法
- 関数のパラメータ化
-
@pytest.mark.parametrize()
マーカーを使う
-
- フィクスチャのパラメータ化
@pytest.fixture(params=[...])
- パラメータのあたいごとにセットアップ、ティアダウンを実行する必要がある際に利用する
-
pytest_generate_tests
を使ってパラメータ化- 公式の例
- pytestのコマンドラインのオプションを作成してパラメータリストから選択できる
- 関数のパラメータ化
- より複雑なパラメータ化は16章
疑問・確認
-
pytest_generate_tests
の使い方はわかったが、使い所のイメージがまだそんなに湧いていない
6章:マーカー
理解
-
@pytest.mark.skip
,@pytest.mark.skipif
,@pytest.mark.xfail
を使って、まだ実装していなかったりバグがあるところのテストをスキップ/通すことができる- ただし、
reason
引数に必ず理由を書く! - TDDで進める場合など初めにxfailをつけておき、実装したものから外していくような使い方が便利
- バグを見つけたが、修正に時間がかかり一旦テストを通しておかなければならない場合に便利
- xfailのstrict=True/Falseは設定ファイルで設定できる
- ただし、
- オリジナルのマーカーは設定ファイルに記述する
- デフォルトの設定だと定義していないmarkerを指定しても実行自体ははしる(警告は出る)。設定ファイルに
--strict-markers
を設定しておくことで、定義していないmarker名が指定されるとエラーになる-
--strict-markers
は設定しておくのがベター - オプション
-ra
でテストがうまくいかない理由を出力できるので、これも設定しておくのがベター
-
- FakerというPythonパッケージを利用することでダミーデータを生成するpytestフィクスチャを使えるようになる
疑問・確認
- Fakerの使い方は要確認