はじめに
「触っていないはずの画面が、なぜか壊れている」——リリース後にそんな報告を受けたこと、ありませんか。
修正したのはAだったのに、見えないところでBが連鎖して壊れる。
自分も何度か経験しました。
こういうとき、つい「念のため全部のテストを流せばよかった」と思ってしまいます。
けれど全件再実行は思ったほど安全策ではなく、何を流すかを 設計する ことの方が重要です。
回帰テストを「やる作業」から「設計対象」に切り替える視点を見ていきます。
TL;DR
- 回帰テストは「やるもの」ではなく 設計するもの。何を流すか、どう育てるか、結果をどう読むかまで含めて考える
- 全件再実行だけに頼ると限界がある。変更の影響範囲を見立ててから 流すテストを選ぶ
- スイートは資産。育て、刈り込み、結果を読み取るところまでが回帰テストの仕事
デグレはなぜ起きるのか — 「直したら壊れた」の構造
回帰テストの話に入る前に、そもそもなぜ修正が既存機能を壊すのかを整理します。
デグレ、つまり直したつもりが別の既存機能を壊してしまう構造が見えると、なぜ「全部流す」では足りないのかも見えてきます。
修正は、修正箇所そのものだけで完結しません。共有モジュール・共通データ・関数が「この入力ならこう返すはず」という前提を経由して、別の機能に波及します。
たとえばToDoアプリで「完了済みは一覧に表示しない」という挙動を直したとします。
一覧側だけ触ったつもりでも、同じフィルタ関数を使っている検索機能の結果からも、完了済みのToDoが消えてしまう。
こうした波及は、修正したファイルを見ているだけでは見えません。
ここで重要なのは、テストケースを積み上げても「修正がどこに波及するか」の見立てがなければ、テスト対象から漏れる場所は出てくるという点です。
網羅は「機能ごとの正しさ」を担保しますが、デグレは「機能をまたいだ副作用」で起きます。網羅と影響度分析は別レイヤーの仕事です。
何が壊れうるかを先に見立てる こと。この「見立て」こそが、次のセクションから扱う回帰テスト設計の中核です。
「全部流す」だけでは足りない — 全件再実行の限界
波及が起こりうるなら、いっそ「変更があるたびに全てのテストを流せばいい」と考えたくなります。素朴で安全に見えるこの方針だけに頼ると、なぜ限界が出るのかを見ます。
全件再実行は、3つの面で限界にぶつかりやすい方針です。
| 観点 | 全件再実行 | 選択的再実行 |
|---|---|---|
| 実行時間 | スイート規模に比例して伸びる | 影響範囲に応じて圧縮できる |
| 失敗時の原因特定 | どこから探すかが定まらない | 修正と関連づけて切り分けやすい |
| スイート膨張への耐性 | 限界が来ると運用が止まる | 育て続けられる |
| 思考の有無 | 「とりあえず全部」で止まる | 「何を選ぶか」で考え続ける |
回帰テストでは、変更の影響範囲に応じて流すテストを選ぶ考え方が重要になります。こうした考え方は、選択的再実行と呼ばれます。
もちろん、選択的再実行にも影響度分析を外すリスクがあります。だからこそ、スモークテスト(製品が最低限起動・基本動作するかを確認する短い一群のテスト)や、夜間・リリース前の全件実行と組み合わせるのが現実的です。
特に最近は、AIにテストを量産させる現場が増えました。
テストケース自体は人間が書くより速く積み上がっていきますが、その分スイートも肥大化します。
全件再実行だけに頼ると、テスト数の増加に追従しにくくなります。
AIで増える時代だからこそ、何を流すかを選ぶ判断軸が、人間の側で必要になります。
では、何を基準に選べばよいのか。ここから技法の話に入ります。
影響度分析 — 何が壊れうるかを先に見立てる
まず必要なのが、変更の波及範囲を先に見立てることです。この記事ではこれを影響度分析と呼び、変更がどこまで波及しそうかを整理します。
見立てに使う情報は、現場にすでにあるものです。
- 修正したファイル・関数・モジュール
- それらを呼び出している(依存している)箇所
- 過去に不具合が集中した領域
- 利用頻度の高い経路(ログイン・主要画面・決済など)
たとえばパスワード変更のバリデーションだけ直しても、同じ関数をログインも使っていればログインまで波及し、見落とせば壊れたままリリースされかねません。
ここで意識したいのが、影響度(修正が波及する範囲の広さ)と重要度(そのバグそのものの深刻さ)の違いです。
「小さくて簡単な修正」だからといって影響範囲も小さいとは限らず、1行のバリデーション修正が共有関数を経由して10機能に波及することは普通に起こります。
そのため、回帰テストでは「修正の大きさ」ではなく、影響度と重要度を組み合わせて選びます。特に共有部品や共通ロジックに触れたときは、軽微な修正でも広めに見る判断が必要です。
優先度で選ぶ — P0/P1/P2 という設計言語
影響度分析で範囲を地図化できたら、次は どの順番で、どこまで 流すかです。
ここで使うのが、テストケース側に振っておく 優先度 という設計言語です。
優先度は、テストケースに事前にラベルを付けておく仕組みです。代表的な3段階を次のように使い分けます。
| ラベル | 守る対象 | 例 |
|---|---|---|
| P0 | サービスの成立に必要な基本経路 | ログイン、画面起動、決済の主経路 |
| P1 | 主要な通常機能 | プロフィール編集、検索、一覧表示 |
| P2 | 補助機能・例外系 | 詳細フィルタ、エクスポート、設定の細部 |
利点は「個人の経験で決める」状態から「ラベルで決まる」状態に切り替えられる点で、AIが書いたテストでもラベルを振れば同じ仕組みで選別できます。
変更側を見る影響度分析と、テスト側に付けた優先度を組み合わせると、「何を流すか」が自動的に立ち上がります。
| 影響範囲 \ 優先度 | P0(基本機能) | P1(通常機能) | P2(補助機能) |
|---|---|---|---|
| 狭い(局所的な修正) | 該当領域のP0 | 該当領域のP1 | 流さない |
| 中程度(複数機能に波及) | 全P0 | 該当領域のP1 | 該当領域のみ |
| 広い(共有モジュール変更) | 全P0 | 全P1 | 選抜したP2 |
肝は3パターンの暗記ではなく、影響範囲が狭ければコアに絞り、広ければ外側へ拡大する という連続的なグラデーションを設計として持つことです。
表の組み合わせは現場の文脈(リリース直前/コンポーネントテスト中/重大な機能改修)で粒度調整できます。
重要なのは2軸を持ち、その交点で選び方を決められるようにしておくことです。
2軸を持つと、「なぜそのテストを流したのか」を後から説明できる状態になります。これが、回帰テストを「設計対象」と呼ぶ理由です。
スイートは資産 — 再評価・追加・除去で育てる
選ぶ元になる回帰テストスイートが古いと、選択の質も落ちるので、スイート自体を資産として育てます。
スイートは機能の追加・廃止・仕様変更で時間とともに変質し、放置すれば「実行に時間はかかるのに、肝心な領域は守られていない」状態に陥ります。
メンテナンスで見るポイントは、おおまかに3つです。
- 追加: 新しく見つかった欠陥領域、新規機能のクリティカルパスをスイートに入れる
- 除去: 廃止された機能、安定して長期間問題が出ない領域、価値の低いネガティブケースを抜く
- 再評価: 前回の合否や過去の前提に引っ張られず、現在の仕様に照らしてテストの価値を見直す
このうち混同しやすいのが、リランと再評価です。リランは、過去と同じ結果が出ることを期待して再実行することを指します。
| 観点 | リラン | 再評価 |
|---|---|---|
| 見方 | 前回と同じ結果になるかを見る | 現在の仕様で正しいかを見る |
| 使う場面 | 軽微な修正後の確認 | 大きな仕様変更・最終回帰 |
| 注意点 | 前回結果に引っ張られやすい | 仕様確認のコストがかかる |
リランでは前回の「合格」が無意識のバイアスになるので、大きな仕様変更や最終回帰の前には、過去の合否に引っ張られず、現在の仕様に照らして見直します。
「前回通ったから今回も通るだろう」という暗黙の前提は、大きな変更時には危険です。回帰テストは「未来は過去の延長」を前提にしない、という姿勢で扱います。
「テストを書いたら終わり」ではなく、「書いた瞬間から劣化が始まる」と捉えると、育て・刈り込み・再評価の運用そのものが回帰テスト設計の一部になります。
結果を読む — 「前回パス・今回フェイル」が回帰失敗のシグナル
「何を流すか」「どう育てるか」を設計しても、結果の読み方を設計に組み込まないと、最後の判定でつまずきます。結果の読み方も設計の一部です。
回帰テストの結果は、合格率の数字を眺めるだけでは判定できません。前回と今回の 差分 を見ます。差分のパターンは、おおむね次の4象限で整理できます。
| 前回 \ 今回 | パス | フェイル |
|---|---|---|
| パス | 期待どおり(変化なし) | 回帰失敗(修正の副作用) |
| フェイル | 修正が効いた | 別問題、または該当修正なし |
ここで一番重要なのは、左下の「前回パス・今回フェイル」です。
これが回帰失敗——本来動いていた機能が、修正によって壊れたことを示すシグナルです。
たとえ全体の合格率が95%だったとしても、ここに1件でも該当があれば、それは「合格率の95%」ではなく「壊した1件」として読まなければいけません。
右下の「前回フェイル・今回フェイル」は、対応する修正が今回入っていないなら、回帰の判定からは外します(既知問題として別管理)。
ワークアラウンドで運用回避できる既知不具合は、回帰失敗とは切り分けて、既知問題として別管理することもあります。
回帰テストの本質は、流したテスト数や合格率ではなく、差分の意味づけ にあります。
おわりに — 検出から予防へ
回帰テストは「壊れたものを見つける」だけの作業ではありません。
「何が壊れうるかを先に見立て、選び、育て、結果を読む」という、壊さない構造を作る 取り組みです。
デグレは偶然防ぐものではなく、技法で減らしていくもの——この視点は、テストを実行する人だけでなく、設計やレビューに関わる人にも効いてきます。
AIが大量のテストコードを書ける時代、テストを「増やすこと」自体は安価になりました。
だからこそ、何を残し、何を捨て、どこに重みをかけるかを言語化する仕事が、人間の側に残ります。
回帰スイートを資産として扱う視点を持つと、テストの量ではなく、設計の質で品質を語れるようになります。
