mcpField
P
python-testing

python-testing

github.com/ahgraberテスト・品質681 回インストール2 日前に更新
リポジトリ

python-testing について

python-testing は、Python テストを作成またはレビューする開発者向けのスキルです。観測可能な振る舞い、決定性のあるユニットテスト、モジュール境界でのパッチに加え、回帰、非同期ライフサイクル、Python バージョン関連のテストを扱います。

主な機能

  1. 01振る舞いと契約のテスト
  2. 02高速で決定性のあるユニットテスト
  3. 03モジュール境界でのパッチ
  4. 04autospec と Fake の活用
  5. 05非同期のクリーンアップとキャンセルの検証
  6. 06Python バージョンマトリックスへの対応

活用シーン

  1. 01実装詳細に依存するテストのレビュー
  2. 02不具合修正の回帰テスト追加
  3. 03不安定または遅いテストの調査
  4. 04非同期のクリーンアップとキャンセル経路のテスト

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ahgraber/skills --skill python-testing

インストール後、Claude Code で/python-testingを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
async-and-concurrency-testing.md
free-threaded-testing.md
multi-python-testing.md
pytest-practices.md
reliability-lifecycle-testing.md
testing-strategy.md
scripts/
test_pypi_security_audit.py
test_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.md
  • references/pytest-practices.md
  • references/async-and-concurrency-testing.md
  • references/reliability-lifecycle-testing.md
  • references/multi-python-testing.md
  • references/free-threaded-testing.md
  • writing-tests スキル — 言語に依存しない基礎(AAA、命名、テストダブル、テストポートフォリオの戦略)

コメント