| id | test-assertion-effectiveness |
| name | Test Assertion Effectiveness 常に PASS するテストの検出 |
| description | テストは存在するがアサーションが実質何も検証しておらず、実装が壊れても落ちない(常に PASS する)構造を diff-time で検出する。Check 1 missing assertion(テスト本体にアサーションが無い)、Check 2 tautological assertion(定数同士・入力自身・mock の戻り値自身を assert し SUT に依存しない)、Check 3 nonexistent expected literal(assertDontSee / assertNotContains 等の期待文字列が対象ファイルに実在しない)、Check 4 stale expected value(同一 diff で対象の出力が変わったのに期待値が据え置き)、Check 5 unscoped expectation(汎用的な属性・クラスを応答全体に対して assert し対象要素にスコープされていない)、Check 6 swallowed failure(例外の握り潰しや到達しない位置のアサーションで判定が成立しない)、の 6 Check を対象とする report-only。テストの有無は test-existence、未テスト経路の量は coverage-gap、非決定性は flaky-test、命名は test-naming、JS/TS の un-awaited resolves / rejects は vitest-mock-isolation、tdd-ledger artifact ベースの RED/GREEN 検証は plangate-tdd-evidence、.only / .skip / xit / @ts-ignore と空の catch は heuristic-review.mjs の決定論検出器へ委譲する |
| version | 0.1.0 |
| category | downstream |
| phase | downstream |
| applyTo | ["**/*.{test,spec}.{ts,tsx,js,jsx,mjs,cjs}","**/*Test.php","**/test_*.py","**/*_test.{py,go,rb}","tests/**/*","test/**/*","__tests__/**/*"] |
| tags | ["tests","assertion","assertion-effectiveness","vacuous-test","always-passing","test-quality","downstream"] |
| severity | major |
| inputContext | ["diff","fullFile"] |
| outputKind | ["findings","questions"] |
| modelHint | high-accuracy |
| dependencies | ["code_search"] |
Naming / 命名
skills/README.md の Naming Q0–Q5 に従って決定した。Q0 では外部プロジェクトの成果物を取り込んでいないため「概念の再実装」に分類され、リネーム(新規命名)が既定となる。Q1 は衝突なし(assertion を含む skill id は既存に無い)、Q2・Q3 は参照元の原語が存在しないため適用外、Q4 で既存の test-* 命名ファミリ(test-existence / test-naming / test-plan-review)に整合することを確認し、Q5 で「価値(アサーションが有効であること)を名指す」名として test-assertion-effectiveness を採用した。機構名(tautology 検出・grep 照合)ではなく価値を名指す点が Q5 の要件である。
Pattern declaration
Primary pattern: Reviewer
Secondary patterns: Inversion
Why: アサーションの形はパターンとして拾えるが、「そのアサーションが SUT の挙動に依存しているか」の判定は意味的であり、期待値の照合先(テンプレート・コンポーネント)が discover できない差分では実行を止めるゲートが必要である。
Goal / 目的
テストの「有無」や「粒度」は既存 skill が見るが、書かれたアサーションが実際に失敗しうるかは誰も見ていない。アサーションが無効なテストは行を通過するためカバレッジ指標にも現れず、CI が緑であることも有効性の証明にならない(レビュー時点の CI が古い sha で緑だった実例が #1684 に記録されている)。この盲点を diff-time の静的観点として埋める。
次の 6 Check のいずれかに該当し、そのテストが実装の退行を検知できないと読み取れる場合に指摘する。report-only(ADR-005)であり、finding / question のみを出力して自動修正はしない。
Non-goals / 扱わないこと(委譲表)
| 隣接領域 | 委譲先 | 分界 |
|---|
| テストが存在しない | test-existence | 委譲先は「変更コードに対応するテストが差分に無い」。本 skill は逆にテストがある差分にだけ働く(委譲先はテスト差分があると黙る前提のため) |
| 未テスト経路・分岐・境界の量 | coverage-gap | 委譲先は「その経路のテストが存在しない」。本 skill は「テストは存在するがアサーションが落ちない」 |
| 実行ごとに結果が変わる不安定さ | flaky-test | 委譲先は非決定性。本 skill は決定論的に必ず PASS する構造 |
describe / it の命名・構造 | test-naming | 命名の明瞭さは対象外。名前が適切でもアサーションが無効なら本 skill が扱う |
JS / TS の un-awaited expect(...).resolves / .rejects | vitest-mock-isolation | 委譲先が「常に pass する空 assertion」として既に所有する。async-correctness も本番コード側からここへ委譲済みであり、三重管理にしない |
tdd-ledger artifact による RED / GREEN 証跡の検証 | plangate-tdd-evidence | 委譲先は artifact 駆動(artifact 非供給の adopter では常に NO_REVIEW)。本 skill はartifact に依存しない diff-time 観点 |
| 影響・失敗系・外部依存を調査した証拠の有無 |