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
3
430
pytest プラグインを開発して DRY に自動テストを書こう
PyCon JP 2024 ミニトーク
Atsushi Inutsuka
September 28, 2024
Tweet
Share
Other Decks in Programming
See All in Programming
ライブ配信サービスの インフラのジレンマ -マルチクラウドに至ったワケ-
mirrativ
2
270
STUNMESH-go: Wireguard NAT穿隧工具的源起與介紹
tjjh89017
0
390
フロントエンドのmonorepo化と責務分離のリアーキテクト
kajitack
2
150
Zendeskのチケットを Amazon Bedrockで 解析した
ryokosuge
3
230
AI OCR API on Lambdaを Datadogで可視化してみた
nealle
0
220
Portapad紹介プレゼンテーション
gotoumakakeru
1
130
オープンセミナー2025@広島「君はどこで動かすか?」アンケート結果
satoshi256kbyte
0
220
Honoアップデート 2025年夏
yusukebe
1
880
AIエージェント開発、DevOps and LLMOps
ymd65536
1
370
Improving my own Ruby thereafter
sisshiki1969
1
140
A Gopher's Guide to Vibe Coding
danicat
0
190
The state patternの実践 個人開発で培ったpractice集
miyanokomiya
0
150
Featured
See All Featured
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
36
2.5k
Docker and Python
trallard
45
3.5k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
6.1k
The World Runs on Bad Software
bkeepers
PRO
70
11k
How to train your dragon (web standard)
notwaldorf
96
6.2k
Bash Introduction
62gerente
614
210k
It's Worth the Effort
3n
187
28k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
161
15k
How to Ace a Technical Interview
jacobian
279
23k
Making the Leap to Tech Lead
cromwellryan
134
9.5k
VelocityConf: Rendering Performance Case Studies
addyosmani
332
24k
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 のプラグインを⾃分で書いてみてはいかがでしょうか