mcpField
P
principle-test-behavior-not-implementation

principle-test-behavior-not-implementation

github.com/michael-denyerテスト・品質3.6k790 回インストール今日更新
リポジトリ

principle-test-behavior-not-implementation について

Test Behavior, Not Implementationは、呼び出し元などが観測できる動作を基準にテストを書く原則です。動作の破損を検出でき、内部構造の変更にも耐えるかでテストを評価します。

主な機能

  1. 01観測可能な契約による動作の定義
  2. 02動作破損を検出できるかの確認
  3. 03内部実装に依存するアサーションの回避
  4. 04要件から期待値を導出
  5. 05契約となる不変条件のテスト

活用シーン

  1. 01内部呼び出しを検証するテストの見直し
  2. 02効果の欠落を検出できるかの評価
  3. 03リファクタリングに耐えるテストの作成

インストール

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

$npx skills add https://github.com/michael-denyer/pstack-claude --skill principle-test-behavior-not-implementation

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

詳細

実装ではなく振る舞いをテストする

テストとは、呼び出し元、エンドユーザー、別のサービスなど、コードを利用する人に対して、コードが何をするかを表明するものです。振る舞いとは、そうした利用者が使用するインターフェースを通じて観察できることです。これには、戻り値、エラー、読み戻せる状態、リクエストの送信、行の書き込み、メッセージの発行など、コード外のシステムに対する影響が含まれます。実装とは、利用者が観察できないものです。非公開のヘルパー、内部の呼び出し順序、中間データ、どの内部の協力オブジェクトが処理したかなどが該当します。

次の2つの変更を想定して、それぞれのテストを評価してください。

  • 振る舞いを壊す。 コードが誤った値を返す、効果を発生させない、または効果を2回発生させるようにします。それでもテストが通るなら、そのテストは何も証明していません。よくある原因は、契約よりも緩いアサーション、テスト対象のコードで計算した期待値、定数やプロンプト文字列を再掲しただけでそれを読み取るコードを実行しないこと、テスト自体が作成したデータに対するアサーションです。
  • 内部を変更する。 観察可能な結果をすべて同じに保ちつつ、内部のコードを再構成します。テストが失敗するなら、そのテストは実装に過度に依存しています。リファクタリングのたびに書き直しが必要になるうえ、それでもバグを検出できません。

最初の変更を検出し、2つ目の変更には耐えるテストを残してください。それ以外は書き直すか削除してください。両方を満たすテストを書くには、具体的な入力を使い、利用者のインターフェースを通じてコードを実行します。期待値はコードの実行結果ではなく、要件から導き出してください。契約で保証されることを、それ以上でもそれ以下でもなくアサートしてください。

重要なのはアサーションの形ではなく、契約です。「カートが空なら決済しない」という約束がある場合、決済クライアントが呼び出されなかったことをアサートするのは振る舞いのテストです。そのテストが呼び出しを検出できることを示すために、決済が発生するケースも組み合わせてください。モックした外部サービスが受け取るペイロードは振る舞いです。外部サービスがそれを観察するからです。内部ヘルパーの呼び出しは、利用者には見えないため実装です。一致するレコードがない場合、空のリストは正確な答えですが、テストで必要なのが何らかの結果だけなら、実のないチェックです。正確なエラーメッセージを固定すると、呼び出し元が参照しない文言にテストが依存します。呼び出し元が分岐に使うエラーの型こそが契約です。

テストでは、呼び出しではなく不変条件を固定することもできます。たとえば、2つのテーブルに存在しなければならないキーや、コンパイル時の型チェックなどです。不変条件が振る舞いです。定数の固定も、その値がユーザーへの約束である場合は振る舞いです。たとえば、ドキュメントに記載されたデフォルト値が該当します。その場合は、その約束を明示してください。

コメント