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
130
pytest プラグインを開発して DRY に自動テストを書こう
PyCon JP 2024 ミニトーク
Atsushi Inutsuka
September 28, 2024
Tweet
Share
Other Decks in Programming
See All in Programming
GraphQLでいい感じの検索APIを作りたい
estie
0
140
利用者視点で考える、イテレータとの上手な付き合い方
syumai
3
180
DjangoNinjaで高速なAPI開発を実現する
masaya00
0
180
Android開発以外のAndroid開発経験の活かしどころ
konifar
2
1.3k
DroidKaigi 2024 - You will 💜 Becoming a fullstack developer with your Android skills
brah
0
110
Shinjuku.rb#95:心の技術書紹介
free_world21
1
120
Remix × Cloudflare Pages × Sentry 奮闘記 / remix-pages-sentry
nkzn
0
280
Crafting Cross-Platform Adventures: Building a Game Engine with Kotlin Multiplatform
dwursteisen
0
330
Infrastructure as Code でセキュリティを楽にしよう!
konokenj
4
1.1k
上手に付き合うコンポーネントテスト
quramy
3
1.1k
GraphQLとGigaViewer for Apps
numeroanddev
4
770
全方位強化 Python 服務可觀測性:以 FastAPI 和 Grafana Stack 為例
blueswen
1
320
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
53
9k
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
Facilitating Awesome Meetings
lara
49
6k
Scaling GitHub
holman
458
140k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
227
52k
Code Review Best Practice
trishagee
62
16k
Testing 201, or: Great Expectations
jmmastey
37
7k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
354
29k
How STYLIGHT went responsive
nonsquared
93
5.1k
ParisWeb 2013: Learning to Love: Crash Course in Emotional UX Design
dotmariusz
109
6.9k
What's new in Ruby 2.0
geeforr
340
31k
Thoughts on Productivity
jonyablonski
67
4.2k
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 のプラグインを⾃分で書いてみてはいかがでしょうか