ソフトウェアテスト戦略は、たいていカバレッジという数字で語られます。しかしカバレッジは、この分野全体のなかで最も情報量の少ない数字です。カバレッジ九十パーセントのコードベースであっても、最もよく使われる経路でバグを本番に送り出すことがあります。カバレッジが測っているのは、テスト実行中にどの行が実行されたかであって、その行について意味のある検証が行われたかどうかではないからです。
自分たちのテストスイートを信頼しているチームは、パーセンテージが最も高いチームではありません。本当に壊れているときにテストが落ち、それ以外のときは静かにしているチームです。そしてこの性質は、お金で買うのがはるかに難しいことが分かっています。
どんなテストについても問う価値のある質問: これが落ちたとき、自分は何をすべきか分かるだろうか。振る舞いが変わったから落ちるテストは、あなたに何かを伝えています。実装の詳細が動いたから落ちるテストは、誰かがリファクタリングしたということしか伝えません。そういう失敗が十分に積み重なると、チームは失敗の内容を読むのをやめ、緑になるまでパイプラインを回し直すだけになります。
なぜカバレッジは誤解を招くのか
カバレッジが答えるのは、その行が実行されたかという問いであり、その行が正しいかという問いではありません。関数を呼び出すだけで何も検証しないテストは、結果の分岐をすべて確認するテストとまったく同じカバレッジを生み出します。
この差には実務上の帰結があります。固定のパーセンテージで目標を設定すると、その数字に届かせるためだけに書かれたテストが確実に生まれます。ささいなゲッターには網羅的なテストが並び、分岐の準備が面倒な決済経路には何も残らない、という状態です。数字は上がりますが、リスクはまったく動きません。
カバレッジが役に立つのは一方向だけです。重要な領域のカバレッジが低いことは、対処する価値のある本物のシグナルです。しかし全体のカバレッジが高いことは何の証拠にもなりません。診断の道具ではなく目標として扱うことこそ、チームが何千ものテストを抱えながら何の自信も持てなくなる典型的な道筋です。
ソフトウェアテスト戦略:どのテストがコストに見合うか
すべてのテストは資産であると同時に負債でもあります。保守が必要で、スイート全体を遅くし、ときには間違った判定を下します。有用な問いは、どのテストがそのコストを回収してくれるのか、です。
単体テストが報われるのは、ロジックが本当に複雑で、インフラから独立している場合です。価格計算のルール、日付の扱い、権限チェック、パーサーなどが該当します。速く、正確で、リファクタリングを生き延びます。記述している振る舞いが実在するものだからです。
結合テストは、多くのチームが思っているよりも大きく報われます。本番のバグの大半は、関数の内部ではなく境界に住んでいるからです。モックに対しては動くのに実際のデータベースでは落ちるクエリ。仕様上は任意でも現実には必ず欠けているフィールドを持つAPI。こうしたテストは遅いですが、その価値があります。
エンドツーエンドテストが報われるのは、ほんの一握りの動線だけです。その数は、口に出して数え上げられる程度に小さく保つべきです。サインアップ、購入、そしてあなたのビジネスがやっているただ一つのこと。これらは遅く、壊れやすく、高くつきます。二百本ものエンドツーエンドテストを抱えたスイートは、チームの苦しみの主要な発生源になります。
多くのコードベースが最終的に落ち着く形は、多数の単体テスト、しっかりした結合テストの層、そして一握りのエンドツーエンド動線です。これがマーティン・ファウラーの言うテストピラミッド です。チームが間違えるのはたいてい真ん中の層です。単体テストとエンドツーエンドテストはあるのに、部品同士がかみ合うかどうかを確かめるものがほとんどない、という状態になります。
フレーキーテストは信頼の問題
二十回に一回落ちるテストは、テストがないよりも悪い存在です。その理由は技術的というより行動的なものです。
スイートにフレーキーなテストが数本混ざると、チームは赤が必ずしも壊れている意味ではないと学習します。再実行が日常になります。やがて本物の失敗も再実行され、三回目で通ったところで誰かがマージします。スイートはシグナルとして機能しなくなり、それでも時間だけは消費し続けます。
不安定さは、本番バグと同じ優先度の欠陥として扱ってください。パイプラインが正直に緑になるよう、まずそのテストを隔離し、そのうえで修正するか削除します。よくある原因は、テスト間で共有された状態、実時間への依存、そしてテストランナーが保証していない実行順序への依存です。
フレーキーテストを削除するのは正当な結末です。誰も信用していないテストは何も守っていませんし、取り除けば少なくとも注意を奪われることはなくなります。
実装ではなく振る舞いをテストする
テストスイートが高くつく最大の原因は、コードが何をするかではなく、どう動くかに結びついたテストです。
すべての依存をモックし、特定のメソッドが特定の引数で呼ばれたことを検証するテストは、振る舞いが変わったかどうかに関係なく、リファクタリングのたびに落ちます。これはまったく逆です。リファクタリングこそ、何も壊れていないとスイートに言ってほしい場面なのに、実際には手作業でつぶすべき五十件の失敗が並びます。
代わりに、結果を検証してください。この入力に対して、システムはこの出力を返す、あるいはこの状態になる。そうしたテストは内部の書き直しを生き延びます。つまり、最もリスクの高い変更のあいだにこそ、あなたを守り続けてくれます。
モックが居場所を得るのは本物の境界です。決済プロバイダ、メール配信サービス、遅いもの、そしてテスト実行中に起こしてはいけない副作用を持つもの。自分のコードの内側では、モックはたいてい得るものより多くを奪います。
CIで回るようにする
誰も待たないスイートは、いずれ飛ばされるスイートです。フル実行に四十分かかるなら、人はプッシュしてそのまま別の作業に移り、フィードバックは別のことを始めたあとに届きます。
分割しましょう。速い単体テストと結合テストは毎回のプッシュで走らせ、数分で答えを返します。遅いエンドツーエンド動線はマージ時、あるいはスケジュール実行に回します。これは2026年英国開発チーム向けCI/CDベストプラクティス のガイドで述べたデプロイの規律と同じ考え方です。
失敗を読めるようにしてください。何を確かめていたのかが分からないまま、アサーションが偽でしたとだけ告げる失敗は、毎回十分の考古学を強います。テストを、それが守っている振る舞いの名前で呼ぶようにすると、失敗一覧はそのまま何が壊れたかの説明に変わります。
そしてスイートを決定的に保ってください。実ネットワーク呼び出しをしない、今日の日付を制御せずに依存しない、実行順序を仮定しない。非決定的なテストはすべて、将来のフレーキーテストです。
テストのないコードベースでどこから始めるか
過去にさかのぼって完全なカバレッジを目指してはいけません。労力は莫大で、その大半は誰も変更しないコードを守るために消えていきます。
まずはバグがお金を失わせる経路から始め、その周りに結合テストを書きます。書いたテスト一本あたりに捕まえるバグの数が最も多いからです。次に、バグ修正のたびにテストを一本追加し、直す前に必ず失敗を再現します。こうすると、カバレッジは欠陥が実際に起きている場所にちょうど育っていきます。それは、リスクがどこに潜んでいるかについて手に入る最良のシグナルです。
Mecanikはカスタムソフトウェア開発 の一環としてテスト戦略のレビューと構築を行っており、たいていはどの失敗が本当に痛いのかという問いから始めます。スイートが大きいのにチームがいまだに緊張しながらデプロイしているなら、問題がテストの本数にあることはめったにありません。
関連記事: 読まれる技術ドキュメント 、初週から成果を出す開発者オンボーディング 、本当に何かを変えるポストモーテム 、APIバージョニング:いつ壊し、どう壊さないか 。
よくある質問
テストカバレッジが高いことは良い目標ですか? それだけでは良い目標になりません。カバレッジが測るのはテスト実行中にどの行が実行されたかであって、その行について意味のある検証が行われたかどうかではありません。そのため、関数を呼ぶだけで何も検証しないテストも、すべての分岐を確認するテストと同じ点数になります。重要な経路のカバレッジが低いことは有用なシグナルですが、全体のパーセンテージが高いことはたいした証拠にはなりません。
単体テスト、結合テスト、エンドツーエンドテストの適切な比率は何ですか? 本当に複雑なロジックには多数の単体テスト、本番バグの大半が境界に住んでいるためしっかりした結合テストの層、そして口に出して数え上げられる程度の少数のエンドツーエンド動線です。多くのチームは真ん中の層を誤ります。単体テストとエンドツーエンドテストはあるのに、部品同士がかみ合うかを確かめるものがほとんどないのです。
フレーキーテストにはどう対処すべきですか? 本番バグと同じ優先度の欠陥として扱ってください。パイプラインが正直であり続けるよう、まずそのテストを隔離し、そのうえで修正するか削除します。スイートにフレーキーなテストが数本混ざると、チームは赤が壊れている意味ではないと学習し、反射的に再実行するようになり、やがて本物の失敗をマージしてしまいます。フレーキーテストを削除するのは正当な結末です。
テストで依存関係をモックすべきですか? 本物の境界であれば、はい。決済プロバイダ、メール配信サービス、遅いものや副作用を持つものです。自分のコードの内側では、モックはたいてい得るものより多くを奪います。特定のメソッドが特定の引数で呼ばれたことを検証すると、振る舞いが変わったかどうかに関係なく、リファクタリングのたびにテストが落ちるからです。
テストが一本もないコードベースにどうテストを足せばよいですか? 過去にさかのぼって完全なカバレッジを目指してはいけません。バグがお金を失わせる経路の周りに結合テストを書いてください。書いたテスト一本あたりに捕まえるバグの数が最も多いからです。次に、バグ修正のたびにテストを一本追加し、直す前に失敗を再現します。そうすれば、カバレッジは欠陥が実際に起きている場所にちょうど育っていきます。
コメント