Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
pytest プラグインを開発して DRY に自動テストを書こう
Search
Atsushi Inutsuka
September 28, 2024
Programming
2
410
pytest プラグインを開発して DRY に自動テストを書こう
PyCon JP 2024 ミニトーク
Atsushi Inutsuka
September 28, 2024
Tweet
Share
Other Decks in Programming
See All in Programming
状態遷移図を書こう / Sequence Chart vs State Diagram
orgachem
PRO
1
120
AI駆動のマルチエージェントによる業務フロー自動化の設計と実践
h_okkah
0
170
PHPでWebSocketサーバーを実装しよう2025
kubotak
0
290
The Modern View Layer Rails Deserves: A Vision For 2025 And Beyond @ RailsConf 2025, Philadelphia, PA
marcoroth
2
410
地方に住むエンジニアの残酷な現実とキャリア論
ichimichi
5
1.6k
Is Xcode slowly dying out in 2025?
uetyo
1
280
おやつのお供はお決まりですか?@WWDC25 Recap -Japan-\(region).swift
shingangan
0
140
システム成長を止めない!本番無停止テーブル移行の全貌
sakawe_ee
1
210
脱Riverpod?fqueryで考える、TanStack Queryライクなアーキテクチャの可能性
ostk0069
0
170
猫と暮らす Google Nest Cam生活🐈 / WebRTC with Google Nest Cam
yutailang0119
0
150
AI時代の『改訂新版 良いコード/悪いコードで学ぶ設計入門』 / ai-good-code-bad-code
minodriven
20
7.6k
なぜ「共通化」を考え、失敗を繰り返すのか
rinchoku
1
650
Featured
See All Featured
How to Think Like a Performance Engineer
csswizardry
25
1.7k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
181
54k
Unsuck your backbone
ammeep
671
58k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
44
2.4k
A better future with KSS
kneath
238
17k
A Modern Web Designer's Workflow
chriscoyier
695
190k
How GitHub (no longer) Works
holman
314
140k
For a Future-Friendly Web
brad_frost
179
9.8k
The Pragmatic Product Professional
lauravandoore
35
6.7k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
161
15k
Automating Front-end Workflow
addyosmani
1370
200k
Making the Leap to Tech Lead
cromwellryan
134
9.4k
Transcript
pytest プラグインを開発して DRY に⾃動テストを書こう PyCon JP 2024 ミニトーク
⾃⼰紹介 2 ⽝束 敦史 (Atsushi Inutsuka) SNS GitHub : inuatsu
X : sekainoinuatsu エンジニアリングマネージャ @ シンプルフォーム株式会社 ⾦融機関などで、法⼈⼝座開設時などに実施が必要な「法⼈の審査業務」において使っていただく プロダクトを開発し、SaaS サービスとして提供しています
発表を聞いて持ち帰っていただける知識 pytest のプラグインを使って何ができるか pytest のプラグインの実装の具体例 例としてデータベースへの読み書きを伴う⾃動テストを並列実⾏する実装を取り上げます pytest のプラグインの動作を保証するためのテストの書き⽅
4 pytest プラグイン開発を考えた背景
直⾯していた課題 以下のような構成の Python ディレクトリがあると想定
直⾯していた課題 以下のような構成の Python ディレクトリがあると想定 ⾊々なところに conftest.py が ある状態になる
直⾯していた課題 開発者から以下のような声が上がるようになりました ディレクトリごとに同じような factory や conftest 記述するの無駄な気がしてきた ディレクトリによって conftest の書きっぷりが異
なっていて認知負荷が⾼め… conftest.py に毎回 MySQL のコンテナの設定周りで 同じようなコードを書いているの、何かしら共通化 できないだろうか
直⾯していた課題 開発者から以下のような声が上がるようになりました ディレクトリごとに同じような factory や conftest 記述するの無駄な気がしてきた ディレクトリによって conftest の書きっぷりが異
なっていて認知負荷が⾼め… conftest.py に毎回 MySQL のコンテナの設定周りで 同じようなコードを書いているの、何かしら共通化 できないだろうか ⇒ 確かに、同じようなコードを⾊々なところに書いているのは DRY じゃない気がする…🤔
発想 同じような factory や conftest.py を記述しているのであれば、テストを実装する際 共通で必要な前処理∕後処理をまとめた pytest プラグインを作ればよいのでは?
発想 同じような factory や conftest.py を記述しているのであれば、テストを実装する際 共通で必要な前処理∕後処理をまとめた pytest プラグインを作ればよいのでは? pytest
プラグインとは? pytest の機能を拡張するために、hook 関数を使って pytest の様々なイベントに 対して特定の処理を実⾏できるようにしたもの 例えば、カバレッジレポートを出すのに使う pytest-cov などもプラグインの⼀種
pytest プラグインで提供したい機能 以下のような処理を全てのディレクトリの conftest.py で書いていたので、 プラグインの機能として提供することを検討しました Docker で MySQL のコンテナを起動する
起動した MySQL コンテナが healthy になるまで待機する 起動した MySQL コンテナの DB にデータベースを作成する 起動した MySQL コンテナの DB セッションを提供する factory およびそのセッションを提供する テストメソッドごとにデータベースのトランザクションを rollback する
12 pytest プラグインの実装準備
ディレクトリ構成 cookiecutter-pytest-plugin などを参考に、以下のようなディレクトリ構成にします libs ディレクトリ内に pytest-common というディレ クトリを追加
プラグインをインストールできるようにする pytest は、pytest11 というエントリポイントを探してプラグインを発⾒するので、 エントリポイントを提供する必要があります ◦ Poetry を使っている場合、プラグインのディレクトリの pyproject.toml に以下の記述を
追加します
15 pytest プラグインの機能開発
プラグインで提供する機能 先ほど⾔及した内、太字の 3 つに絞って具体的な実装を紹介します Docker で MySQL のコンテナを起動する 起動した MySQL
コンテナが healthy になるまで待機する 起動した MySQL コンテナの DB にデータベースを作成する 起動した MySQL コンテナの DB セッションを提供する factory およびそのセッションを提供する テストメソッドごとにデータベースのトランザクションを rollback する
データベースアクセスを伴うテスト 今回は、データベースアクセスを伴うテストはコンテナでデータベースを起動して、 コンテナ上のデータベースにアクセスしてテストをすることを前提とします データベースアクセスを伴うテストを実⾏する場合、テストケースの数が増えると テストにかかる時間が⻑くなることが懸念されます テストを並列実⾏できるようにすることで、必要に応じてテスト時間を短縮できるように します
テストの並列実⾏ DB アクセスを伴うテストがあると、pytest-xdist などのプラグインを使って並列実⾏ しても、他プロセスで書き込まれたレコードによりテスト結果が変わり得ます プロセス間でテスト結果に影響を与えない⼯夫として以下の⽅針を採⽤ ⼀つの MySQL コンテナ内に複数のデータベースを作成し、各プロセスがテスト実⾏中に 固有のデータベースを使うようにすることで、並列実⾏時のプロセス間の独⽴性を担保
MySQL コンテナの起動
MySQL コンテナの削除 ローカルで実⾏する時にテスト実⾏時間を少しでも短縮できるよう、 VOLUME_CLEANUP の環境変数を設定していたらコンテナを削除する際に ボリュームを削除しないように実装
単⼀プロセス∕複数プロセスでの MySQL コンテナ起動∕削除 単⼀プロセスか複数プロセスかにより条件分岐します pytest-xdist をインストールすると、単⼀プロセスで起動する場合 worker_id fixture が "master"
の値を返すので、それにより単⼀プロセスであることを判定 複数プロセスの場合、pytest-xdist を使うと session スコープの fixture は テストプロセスごとに実⾏されるため、複数回実⾏されてしまいます pytest-xdist のドキュメントで、filelock を使って session スコープの fixture が⼀度だけ 実⾏されるように保証する⽅法が紹介されているので、それを参考に実装
単⼀プロセス∕複数プロセスでの MySQL コンテナ起動∕削除
データベース作成 pytest-xdist では session スコープの fixture はプロセスごとに実⾏されることに ⾔及しましたが、その性質を使うことでプロセスごとに固有のデータベースを 作成して使う実装を実現できます pytest-xdist
を使うと、各テストプロセスで PYTEST_XDIST_WORKER という環境変数に ワーカ名が定義されます この性質を使い、test_db_{ワーカ名} という命名ルールでデータベースを作成し、 テストプロセス内でそのデータベースで DB セッションを提供するようにします。
データベース作成
25 pytest プラグインの⾃動テスト
テストを書くのに使えるプラグイン pytest には pytester というプラグインがあり、プラグインのコードのテストを 書くのに活⽤できます ◦ pytester はデフォルトでは無効になっており、tests ディレクトリ内の
conftest.py に 以下の記述をすることで有効化できます。 ◦ pytester では⼀時的な conftest.py やテストファイルを作成する API が提供されており、 それを活⽤することでプラグインの動作を検証することができます。
実際にテストを書いてみる
28 pytest プラグインの導⼊
プラグインのインストール 導⼊したいディレクトリでプラグインをインストールするだけで、プラグインに 実装されている fixture が使えるようになります ◦ Poetry で依存を管理している場合のインストールコマンド例 ◦ プラグインの中に書いた
fixture は⾊々なプロジェクトディレクトリの conftest.py に 書く必要がなくなり、テストの前処理、後処理を DRY に書くことができます
テスト実⾏時にプラグインが有効になっていることの確認⽅法 テスト実⾏時に最初に表⽰されるログにおいて、今回実装したプラグインの名前が plugins の箇所に表⽰されていれば、プラグインが有効になっています
31 まとめ
まとめ 1. ⾃分が管理するプロジェクトで導⼊できる pytest のプラグイン、意外と簡単に 作ることができます 2. ⾊々なディレクトリで conftest.py を書いていて、同じようなテストの前処理∕
後処理を全ての conftest.py で書いてしまっているな…という⽅は、 pytest のプラグインを⾃分で書いてみてはいかがでしょうか