principle-test-behavior-not-implementation について
Test Behavior, Not Implementation は、内部呼び出しや定数の再確認ではなく、観察可能な振る舞いを検証するテストスキルです。弱いアサーションの見分け方と、テストの修正・削除方法を示します。
主な機能
- 01観察可能な振る舞いの検証
- 02弱い・自己参照アサーションの特定
- 03定数固定を振る舞いの検査に置換
- 04欠陥を検出できないテストの削除
活用シーン
- 01既存テストを残すか検討
- 02具体的な入力に対するアサーションの改善
- 03欠陥検出につながらないテストの整理
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ hachej/ boring-stack --skill principle-test-behavior-not-implementationインストール後、Claude Code で/principle-test-behavior-not-implementationを入力して読み込まれたか確認します。
同梱ファイルLICENSE
詳細
実装ではなく動作をテストする
テストでは、ユーザーが使うのと同じ方法でコードを呼び出し、観察できる結果を具体的な期待値と照合します。コードが行った呼び出しを検証したり、コード内の定数をそのまま言い換えたりするテストは、どちらもその目的を果たしません。
確認方法:テストを残す前に、インポートしているすべての関数が undefined を返したとしても、そのテストに合格するかを考えてください。合格するなら、動作を観察しておらず、不具合があっても失敗しません。アサーションを書き直すか、テストを削除してください。
理由: 不具合があっても失敗しないテストは、CI の実行時間とレビューの労力を浪費し、何も検出しません。定数の値を固定して検証するテストも、誰かがその定数や、テストがそのまま言い換えているプロンプトを編集すると失敗するため、その編集を妨げます。
インポートしたすべての関数が undefined を返しても合格する、よくある 5 つの形式:
- アサーションが弱い、またはない。
expectがないか、toBeDefined、toBeTruthy、not.toThrow、toBeInstanceOf、toBeGreaterThan(0)だけを使っている。 - モックの呼び出し、または値がないことだけを検証する。
toHaveBeenCalled、not.toHaveBeenCalled、toBeUndefined、toEqual([])、toHaveLength(0)、not.toBe(wrongValue)だけを使っている。 - 自己参照型。 期待値がテスト対象のコードから得られる。例:
expect(f(a)).toBe(f(a))、expect(parsed.url).toBe(buildUrl(...))。 - 定数の値を固定して検証する。 手動管理されている定数、設定のデフォルト値、テーブルの行、プロンプト文字列をそのままアサーションに記述する。例:
expect(LIMITS.maxTools).toBe(8)、expect(PROMPT).toContain("You are")。 - フィクスチャでフィクスチャを検証する。 アサーションがテストで作成したデータ、または
beforeEachで計算した値を読み取り、テスト本体内で対象の処理を実行していない。
修正方法: テスト本体で具体的な入力を使って対象を呼び出し、リテラルな出力または観察可能な効果を検証します。例:expect(slugify("Hello, World!")).toBe("hello-world")。ある入力で値がないことを検証する場合は、同じテストで別の入力に対して値が存在することも検証します。定数については、値をそのまま言い換えるのではなく、具体的な入力を使って定数を読み取る仕組みをテストします。モックについては、呼び出されたことではなく、受け取ったペイロードまたは呼び出し後の状態を検証します。そのようなアサーションが存在しない場合は、テストを削除してください。
残してよいのは、 テーブルの行どうしの関係(2 つのテーブルに存在するキー、実在する親など)をテストするものと、*.test-d.ts ファイル内のコンパイル時チェックです。