principle-test-behavior-not-implementation について
テストの品質を、ユーザーに見える動作の不具合を検出でき、内部のリファクタリング後も有効かどうかで評価する開発者向けスキルです。
主な機能
- 01観測可能な動作をテスト
- 02リファクタリング耐性の確認
- 03インターフェース入力で実行
- 04要件から期待値を導出
- 05契約上の結果を検証
活用シーン
- 01回帰を見逃すテストのレビュー
- 02内部ヘルパー依存テストの置き換え
- 03外部への作用とエラーの検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ cursor/ plugins --skill principle-test-behavior-not-implementationインストール後、Claude Code で/principle-test-behavior-not-implementationを入力して読み込まれたか確認します。
詳細
実装ではなく振る舞いをテストする
テストとは、コードが利用者(呼び出し元、エンドユーザー、別のサービス)に対して何をするかについての主張です。振る舞いとは、利用者が使用するインターフェースを通じて観察できることです。これには、戻り値、エラー、読み戻せる状態、コードの外部にあるシステムへの作用(リクエストの送信、行の書き込み、メッセージの発行など)が含まれます。実装とは、利用者が観察できないものです。プライベートなヘルパー、内部の呼び出し順序、中間データ、どの内部の協調コンポーネントが処理を担当したか、などが該当します。
次の2つの変更を想定し、それぞれのテストを評価してください。
- 振る舞いを壊す。 コードが誤った値を返す、作用を省略する、または作用を二重に実行するように変更します。それでもテストが通るなら、そのテストは何も証明していません。よくある原因は、契約より緩いアサーション、テスト対象のコードが算出した期待値、値を読み取るコードを実行せずに定数やプロンプト文字列を書き直しただけのテスト、そしてテスト自身が作成したデータに対するアサーションです。
- 内部を変更する。 観察可能な結果はすべて同じまま、コードの内部構造を変更します。そのときテストが失敗するなら、テストは実装に過度に依存しています。リファクタリングのたびに書き直す必要がある一方で、バグは検出できません。
最初の変更を検出し、2つ目の変更には耐えるテストは残してください。それ以外は書き直すか削除してください。両方を満たすテストを書くには、具体的な入力を用いて、利用者が使うインターフェースからコードを動かします。期待値はコードの実行結果ではなく、要件から導き出してください。契約が約束する内容を、過不足なくアサートしてください。
判断基準はアサーションの形ではなく、契約です。「空のカートには決して課金しない」という約束がある場合、決済クライアントが呼び出されなかったというアサーションは振る舞いを検証しています。テストで呼び出しを検出できることを示すため、課金が発生するケースも組み合わせてください。モックした外部サービスが受け取るペイロードは、そのサービスが観察するものなので振る舞いです。内部ヘルパーの呼び出しは、利用者には見えないため実装です。該当するレコードがない場合、空のリストが厳密な答えになることもあれば、テストで何らかの結果さえ得られればよいときには、形だけのチェックにもなります。呼び出し元が参照しない正確なエラーメッセージをアサートすると、文言に過度に依存します。呼び出し元が分岐に使うエラーの型こそが契約です。
呼び出しではなく、2つのテーブルに存在しなければならないキーや、コンパイル時の型チェックなどの不変条件をテストで固定することもできます。その不変条件が振る舞いです。