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
330
pytest プラグインを開発して DRY に自動テストを書こう
PyCon JP 2024 ミニトーク
Atsushi Inutsuka
September 28, 2024
Tweet
Share
Other Decks in Programming
See All in Programming
DMMオンラインサロンアプリのSwift化
hayatan
0
230
最近のVS Codeで気になるニュース 2025/01
74th
1
230
PHPで作るWebSocketサーバー ~リアクティブなアプリケーションを知るために~ / WebSocket Server in PHP - To know reactive applications
seike460
PRO
2
800
watsonx.ai Dojo #6 継続的なAIアプリ開発と展開
oniak3ibm
PRO
0
250
盆栽転じて家具となる / Bonsai and Furnitures
aereal
0
2.1k
サーバーゆる勉強会 DBMS の仕組み編
kj455
1
330
[JAWS-UG横浜 #79] re:Invent 2024 の DB アップデートは Multi-Region!
maroon1st
0
120
ecspresso, ecschedule, lambroll を PipeCDプラグインとして動かしてみた (プロトタイプ) / Running ecspresso, ecschedule, and lambroll as PipeCD Plugins (prototype)
tkikuc
2
2.2k
React 19でお手軽にCSS-in-JSを自作する
yukukotani
5
590
DevinとCursorから学ぶAIエージェントメモリーの設計とMoatの考え方
itarutomy
1
460
Scaling your build logic
antalmonori
1
130
.NETでOBS Studio操作してみたけど…… / Operating OBS Studio by .NET
skasweb
0
130
Featured
See All Featured
The Cost Of JavaScript in 2023
addyosmani
47
7.3k
VelocityConf: Rendering Performance Case Studies
addyosmani
327
24k
The World Runs on Bad Software
bkeepers
PRO
66
11k
Music & Morning Musume
bryan
46
6.3k
Unsuck your backbone
ammeep
669
57k
The Pragmatic Product Professional
lauravandoore
32
6.4k
Thoughts on Productivity
jonyablonski
68
4.4k
YesSQL, Process and Tooling at Scale
rocio
170
14k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
3
260
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
174
51k
How GitHub (no longer) Works
holman
312
140k
How to Think Like a Performance Engineer
csswizardry
22
1.3k
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 のプラグインを⾃分で書いてみてはいかがでしょうか