📖 はじめに — カバレッジの数字は、放っておくと嘘をつく
テストカバレッジほど「あるのに信用できない」メトリクスは少ない。数字が高くても、計測から丸ごと抜けている領域があれば意味がないし、ロジックのない DTO が分母に混ざっていれば実態より低く見える。AI コーディングはテストも量産してくれるが、「どこを測れていないか」は誰も教えてくれない。
本章は 2 本のステアリングの実録だ。前半は Python ジョブ群のカバレッジを 96% 一律ゲートに引き上げた話、後半は .NET / フロントエンドの計測そのものの負債を解消した話。共通する結論を先に言う — カバレッジは「上げる」前に「正しく測る」が先である。
🐍 前半: Python ジョブ群を 96% ゲートへ
計画の数字は腐る — Plan 72% vs 実測 29%
Python ジョブ群のカバレッジはジョブごとにバラバラ(ベースライン実測で 7%〜82%)で、CI ゲートも一律ではなかった。是正ステアリングの起票にあたり、まず全ジョブを再実測したところ、いきなり型 3(定量が起票を正当化する)の教材が出た。
計画文書ではあるファイル(SAGA キャンセル監視、約 140 行)のカバレッジを 72% としていたが、実測は 29% — 43 ポイントの乖離があった。計画起案から着手までの数週間で、周辺テストの整理により数字が大きく動いていたのだ。教訓は単純で、着手時に必ず再実測する。計画時の数字を信じて見積もると、+18pt のつもりが +61pt の作業になる。
達成値と、その過程で出た「本当の発見」
最終的に全 5 ジョブが 96% ゲートを通過した(96.01%〜99.54%)。だが本章的に重要なのは数字ではなく、その過程で別エージェントによるテストレビュー(test-reviewer) が発見したものだ。
- 指摘 19 件中 9 件を即時対応、10 件は別 PR に分離 — レビュー指摘を「全部いま直す」と PR が肥大するため、対応とスコープ分離を明示的に裁いた
- 網羅性の強化は具体的だった。例: ステータス 6 値 × 大文字小文字差を parametrize で 15 ケース × 2 ジョブ = 30 ケースに展開
- そして最大の発見 — SAGA キャンセル監視の production コード 140 行と、そのテスト 422 行が、2 つのジョブ間で完全コピペ。合計約 1,124 行の重複が、カバレッジ作業をするまで誰にも認知されていなかった
この 1,124 行への対処が、スコープ規律の見本になった。共通化はカバレッジ回復ステアリングの目的ではないので、その場では直さず、実測値つきで別起票。テストを書くために対象コードを精読する行為は、それ自体が最強のコードレビューであり、型 2(ゼロベースライン確認が兄弟負債を炙り出す)が Python でも発動した形だ。
🔬 後半: 「測れていない」を潰す — .NET / フロントエンドの計測負債
後半のステアリングは、カバレッジレポートの分析から出発して計測自体の負債を 3 種類に腑分けした。ここが本章の目玉だ。
発見 1: BC が丸ごと計測から消えていた
カバレッジ設定を精査すると、ある BC(Category)が coverlet 設定と CI レポート設定の二重除外で、レポートから丸ごと消えていた。誰も意図を覚えていない「無自覚な穴」だ。
対処が興味深い。実体を調査すると、この BC は 6 ファイルで、実ロジックを持つのは 1 クラス(早期リターン分岐 1 つ)だけと判明。オーナー裁定で除外は維持し、代わりに除外理由を両設定ファイルのコメントと ADR に明文化、残る 1 クラスのテスト整備は別起票した。除外をやめて数字を「正しく」することもできたが、それは分母に大量の interface 定義を混ぜるだけ。「無自覚な穴」を「理由が書かれた管理された負債」に変換することが正解だった。
発見 2: 0% クラスの半分は「偽の穴」
カバレッジ 0% のクラスは 47 個あった。愚直に「全部テストを書く」と走り出す前に分類すると、22 個はロジックを持たない DTO / record だった。これらに振る舞いテストを書くのは無意味どころか有害 — アサーションのない「実行するだけテスト」の温床になる。[ExcludeFromCodeCoverage] で計測対象外にし、分母を健全化した。
残る 0% のうち 6 個は未実装のスタブハンドラで、これは「テストがない」のではなく「実装がない」。カバレッジ負債ではなく実装負債として別の台帳に載せた。同じ 0% でも、意味が 3 通りある — 分類してから手を動かすと、無駄なテストを 22 クラス分書かずに済む。
発見 3: 計測ツール自体も疑う
フロントエンドでは、集計スクリプトの Lines 指標が内部データの癖で 99.8% と過大表示されることが判明し、Statements% を正とする判断も入った。ゲートの根拠になる数字は、その数字を作る道具から検証する。第6章の「無スタイル DOM を検査していた」と同型の、計測の真正性の問題である。
確定値と ratchet — ゲートは「今の実力 − 誤検知余裕」から始める
健全化後の確定値は .NET が line 95.5% / branch 86.7%、フロントエンド統合が statements 95.0% / branch 86.5%。CI ゲートの閾値は実測より少し下(例: branch 85)から始め、85 → 88 → 90 と段階的に引き上げる ratchet 方式を採る。
最初から理想値でゲートを張ると、無関係な PR が誤検知で止まりゲートごと無効化される — 第6章の a11y 52 件を todo リスト化したのと同じ判断だ。ゲートの敵は甘さではなく、狼少年化である。
🧾 まとめ
- 計画時のカバレッジ値は腐る。着手時に再実測してから見積もる(72% のつもりが実測 29%)
- テストを書く過程は精読であり、隠れた重複 1,124 行のような兄弟負債を炙り出す。直すかどうかはスコープ規律で裁き、別起票をためらわない
- カバレッジ 0% には 3 つの意味がある — 真の穴(テストを書く)・偽の穴(DTO は分母から除去)・実装負債(別台帳)。分類が先、着手は後
- 計測除外は「無自覚」が罪。理由を設定ファイルと ADR に明文化して管理された負債にする
- ゲートは実測 − 余裕から始めて ratchet で引き上げる。誤検知でゲートを狼少年にしない
テストの「量」を守る仕組みができた。次章は、そのテストが守るべき Python コードの中身 — 握り潰された例外と量産されたスタブの話、Python ジョブ群編へ。
📚 シリーズ記事(ステアリング駆動開発・実践編)
序章
第I部: 技術的負債ドメイン別の実録(総点検ガイド + 8 ドメイン・全 9 回)
- リファクタリング総点検ガイド — 7 つの観点と進め方
- DDD/SOLID/BC 編 — god class 一掃と境界の機械ガード
- SAGA 編 — 新アーキテクチャ挑戦と再発ゲート
- Atomic Design リファクタ編 — 47 page 新規移植
- Storybook × a11y 実機編
- テスト品質・網羅性編(本記事)
- Python ジョブ群編
- パフォーマンス編
- セキュリティ編
第II部: 検証エンジン(クロスファミリー検証・全 6 回)
- 総論 — マルチ LLM の 2 系統と見取り図
- 裏取り編 — +18.1pt 論文の検証
- 設計編 — finder/verifier 分業と逆順禁止
- TDD×ハーネス編 — テスト保護と三層ゲート
- 実装編 — Claude Code の中から Codex を動かす
- モデル戦略編 — ティア割当と「買うか組むか」
終章
- クロスファミリー検証の最終型 —「正しく作る」から「自分で正しさを測り直す」へ — 検証エンジンに「計測」の層をはめ、自己修正ループを閉じる
番外編
- CI テスト 29 分 → 5.6 分 — 検証エンジンの平時運用実録 — 実測が有力仮説を殺し、退行前より速くなった 1 日
- GPT-5.6 sol 切替の当日実録 — もう一つのデフォルト追従 — CLI 更新が黙って替える finder と、当日中の再計測
- 遊休 90% の枠に仕事を振る — Codex 上流調査と verifier バッチ化 — 逆順禁止の境界を ADR で確定し、読む仕事を遊休枠へ移した 1 日
- ハーネスが単一プロジェクトを卒業する — プラグイン化と二層配布 — 4 プロジェクト展開への切り出しと、version + SHA ピンによる非強制追従
- 69分で5リリース — Opus 5 当日対応が暴いた共通ハーネスの死角 — 新モデル対応を起点に、配布・文書・CI の回帰を二消費者で検出した 69 分
関連記事
- TDD(テスト駆動開発) / テスト技法 — 理論編
- 品質ゲート編 — doc-reviewer / test-reviewer の運用