python-testing について
python-testing は、Python テストを作成またはレビューする開発者向けのスキルです。観測可能な振る舞い、決定性のあるユニットテスト、モジュール境界でのパッチに加え、回帰、非同期ライフサイクル、Python バージョン関連のテストを扱います。
主な機能
- 01振る舞いと契約のテスト
- 02高速で決定性のあるユニットテスト
- 03モジュール境界でのパッチ
- 04autospec と Fake の活用
- 05非同期のクリーンアップとキャンセルの検証
- 06Python バージョンマトリックスへの対応
活用シーン
- 01実装詳細に依存するテストのレビュー
- 02不具合修正の回帰テスト追加
- 03不安定または遅いテストの調査
- 04非同期のクリーンアップとキャンセル経路のテスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ ahgraber/ skills --skill python-testingインストール後、Claude Code で/python-testingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/async-and-concurrency-testing.mdfree-threaded-testing.mdmulti-python-testing.mdpytest-practices.mdreliability-lifecycle-testing.mdtesting-strategy.mdscripts/test_pypi_security_audit.pytest_uv_security_audit.py詳細
Python テスト
概要
内部実装ではなく、観察可能な動作と契約をテストします。 ユニットテストは高速かつ決定論的に保ち、モジュール境界でパッチを適用します。
これらは、一般的なケースで推奨されるデフォルト設定です。 デフォルト設定がプロジェクトの制約と合わない場合は、より適した代替案を提示し、トレードオフを明示したうえで、補完的な対策も記載します。
言語に依存しないテストの原則(AAA 構造、命名、テストダブルの分類、テストポートフォリオ戦略)については、writing-tests を参照してください。
このスキルでは、これらの基礎に Python 固有の実践方法を加えています。
呼び出しに関する通知
- このスキルを呼び出す際は、名前
python-testingをユーザーに伝えてください。
使用する場面
- ユニットテスト、統合テスト、信頼性が重視されるテストを作成またはレビューするとき。
- テストが不安定、低速、または実装の詳細に結合しているとき。
- バグ修正後に回帰テストを追加するとき。
- 非同期処理のライフサイクル、キャンセル、クリーンアップ経路をテストするとき。
- 変更に必要なテストカバレッジがわからないとき。
- 複数の Python バージョンにまたがってテストするとき(nox、CI マトリックス)。
- フリースレッド Python(GIL 無効のビルド)でスレッドセーフ性を検証するとき。
使用しない場面:
- データ形状やスキーマの検証のみの場合(
python-types-contractsを参照)。 - 本番環境の可観測性や監視に関する場合(
python-runtime-operationsを参照)。 - テストハーネスの範囲外で並行処理の設計を決める場合(
python-concurrency-performanceを参照)。
クイックリファレンス
- 内部実装ではなく、観察可能な動作をテストします。
- ユニットテストは高速かつ決定論的に保ちます。
- テスト対象のユニットが使用するインポート先で、モジュール境界にパッチを適用します。
- バグ修正には回帰テストを追加します。修正前に失敗するテストを書いてください。
- 該当する場合は、タイムアウト、再試行、キャンセル、クリーンアップのテストも含めます。
- 複数の Python バージョンを扱う場合は、バックエンドに uv を使って nox を使用し、依存関係のマトリックスにはパラメーター化を使用します。
- フリースレッド Python では、
pytest-run-parallelを使用し、PYTHON_GIL=0を設定して、必ず CI のタイムアウトを設定します。
テストダブル
完全な Meszaros の分類(Dummy、Fake、Stub、Spy、Mock)、クラシカル派とモキスト派の違い、一般的な指針については、writing-tests → references/test-doubles.md を参照してください。
Python 固有の注意事項:
unittest.mock の命名は誤解を招きます。
Mock と MagicMock は「Mock」という名前ですが、デフォルトでは Stub として動作します。return_value または side_effect で設定すると、あらかじめ用意した値を返し、自身では呼び出しを検証しません。
.assert_called_with() / .assert_called_once_with() を呼び出した場合にのみ、Mock(振る舞いの検証)になります。
観察可能な出力を検証することを優先してください。
create_autospec() または autospec=True を使用します。
通常の Mock() は、どのような引数でも何も言わずに受け入れます。
create_autospec(SomeClass) は実際のメソッドシグネチャを強制します。呼び出し箇所の不一致があれば、本番環境で TypeError が発生するまで隠れるのではなく、すぐにテストが失敗します。
テスト対象のモジュールで使用されているインポート先にパッチを適用し、元の定義箇所には適用しないでください。
# Wrong: patches the definition; callers in other modules are unaffected
patch("requests.post", ...)
# Right: patches where your module imported it
patch("mymodule.client.requests.post", ...)
プロジェクトですでに使用している場合は、pytest-mock の mocker フィクスチャを検討してください。
pytest のフィクスチャライフサイクルに統合されており、ティアダウンを自動で処理し、テスト関数でデコレーターを重ねる必要がありません。
pytest-mock が既存の依存関係にない場合は、unittest.mock.patch で十分です。利便性だけを理由に追加する必要はありません。
深く連鎖したモックより Fake を優先します。
複数階層の Mock() チェーンよりも、インメモリ実装(FakeRepo、dict を基盤とするストア)を優先してください。
本番環境の呼び出しグラフを模したチェーンは壊れやすく、I/O がロジックから分離されていない兆候です。
変更内容に応じた診断
- 依存関係の更新:
uv run pytest scripts/test_uv_security_audit.py scripts/test_pypi_security_audit.py -vを実行します。test_uv_security_audit.pyはロックファイルに対してuv auditを使用するため、こちらが推奨されます。test_pypi_security_audit.pyは、uv auditを実行できる場合に自動的にスキップされる、pip-audit の代替手段です。 どちらも検出結果があっても失敗せず、警告を出すだけなので、警告を確認してください。 - 非同期処理が多いライフサイクルの変更:
pyleakによる診断を実行します。 - 複数の Python バージョンへの対応に関する変更:
noxで全マトリックスを実行します。 - フリースレッド対応:フリースレッドビルド(3.13t 以降)で
PYTHON_GIL=0 uv run --python 3.Xt pytest --parallel-threads=auto --timeout=300を実行します。
よくある間違い
- 単一の書き込み箇所しかテストしない — 正規のコードパスはテストしても、同じ契約で検証される値を書き込む別のパス(重複排除のショートカット、キャッシュの高速パス、再試行の分岐)をテストしていないことです。
書き込み箇所ごとにテストが必要です。
references/testing-strategy.mdの「複数パスと派生フィールドのパターン」を参照してください。 - 合成後の不変条件が欠落している —
field_a == f(field_b)が必須の関係で、それぞれのフィールドを異なる生成元(リゾルバー、フェッチャー、マージ処理)が書き込む場合、各段階のローカルテストでは、合成後も不変条件が保たれることを証明できません。 組み立て済みの出力に対して、その関係を検証するテストを作成してください。references/testing-strategy.mdの「複数パスと派生フィールドのパターン」を参照してください。 - モック化が深すぎる — モジュール境界の継ぎ目ではなく内部をパッチすると、テストが壊れやすくなり、実装との結び付きが強くなります。
- モック自体をテストしている — 観測可能な出力を検証せずにモックの呼び出し回数を確認しても、動作の証明にはなりません。
- 回帰テストがない — バグを再現するテストを先に作らずに修正すると、バグが再発します。
- 時間や順序が非決定的 — クロックを注入して明示的にソートする代わりに、実時間や辞書・セットの順序に依存することです。
- クリーンアップの検証を省略する — 正常系は検証しても、失敗時やキャンセル時にリソースが解放されることを検証していないことです。
- フリースレッド CI エントリがない — フリースレッド(
tサフィックス付き)のマトリックスエントリを用意せずにマルチスレッドコードをリリースすることです。GIL は競合状態を隠すため、フリースレッド Python がデフォルトになると、そうした問題が表面化します。 - GIL の再有効化を見落とす —
Py_mod_gilを指定せずに C 拡張をインポートすると、GIL が暗黙的に再有効化されます。インポート後にsys._is_gil_enabled()を確認してください。 - YAML のバージョンが浮動小数点数として扱われる — CI マトリックスの YAML で
3.10を引用符で囲まずに記述することです。3.1として解析され、誤った Python がインストールされます。
参考資料
references/testing-strategy.mdreferences/pytest-practices.mdreferences/async-and-concurrency-testing.mdreferences/reliability-lifecycle-testing.mdreferences/multi-python-testing.mdreferences/free-threaded-testing.mdwriting-testsスキル — 言語に依存しない基礎(AAA、命名、テストダブル、テストポートフォリオの戦略)