AIに修正を任せた後、既存の挙動が壊れていないかテスト結果を落ち着いて確認している開発者

AIに直させてもリグレッションを出さない既存テストの渡し方

「ここのバグだけ直して」とAIに頼んだ。直したい所は、たしかに直った。 でも動かしてみたら、まったく関係ないはずの別の画面が壊れている。ログインは通るのに一覧が出ない、金額の計算が微妙にずれた——直したつもりが、別の場所を巻き込んでいた。

この「直した所以外が、いつの間にか壊れている」現象を、リグレッション(デグレ)と呼びます。AIに修正やリファクタを任せると、これが起きるのが怖くて、結局まかせきれない。その気持ちは、とても正しい防衛本能です。あなたのレビューが甘いわけではありません。AIは「頼まれた所」は直せても、「触っていい範囲」と「絶対に変えてはいけない挙動」を、こちらが渡さない限り知らないからです。だからこそ、既存の挙動を守る文脈を、修正を頼む前にこちらから渡す。この記事では、その渡し方と、戻ってきた変更の確認手順を、コピーして使える形で整理します。

結論:AIの修正でリグレッションを防ぐ鍵は、「賢く直させる」ことより「変えていい範囲と、変えてはいけない挙動を先に渡す」ことです。手順は3つ。①修正の前に、既存テストを走らせて「今の緑(通っている状態)」を記録する。これが壊れていないことの基準になります。②AIに頼むとき、直す対象と一緒に「この挙動は変えないで/このテストは緑のままで」という不変条件と、関係する既存テストを渡す。③戻ってきたら、まず既存テストを全部流して、緑が緑のままかを見る。落ちたテストがあれば、それが巻き込み事故の場所です。テストが無い部分を触らせるときは、触る前に「今の動き」をテストで固めてから任せる。守りたい挙動を先に見える形にしておくのが、いちばん確実な歯止めです。

リグレッションが起きるのは、AIが雑だからではありません。 AIに見えているのは「あなたが今回頼んだこと」だけで、その修正がコードベースの他のどことつながっているかは、指示に含めない限り視界の外です。人間なら「ここを変えると、あの機能にも影響するな」と経験でブレーキを踏みますが、AIはブレーキの位置を知りません。そのブレーキ=守りたい挙動を、テストという形で先に渡しておく。今日は、その渡し方を一緒に見ていきましょう。

なぜAIの修正はリグレッションを起こしやすいのか

一つの修正が周囲の機能に波及して壊す様子と、テストで囲って波及を止める様子を対比した図

AIの修正でデグレが出やすいのには、はっきりした理由があります。

まず、AIは「今回の依頼」以外の挙動を知らないこと。「この関数のここを直して」と頼むと、AIはその関数の中で辻褄を合わせます。でも、その関数を呼んでいる別の場所が、直す前の細かい挙動(戻り値の形、例外の投げ方、並び順)に依存していると、そこが静かに壊れます。AIには呼び出し側が見えていません。

次に、「良かれと思って」余計な所まで整えること。頼んだのはバグ修正なのに、ついでに変数名を変えたり、条件を「きれいに」書き直したり、使っていなさそうな分岐を消したり。その「ついで」が、実は誰かが頼りにしていた挙動だった、というのがデグレの典型です。

そして、守りたい挙動が、どこにも書かれていないこと。「上限を超えたら丸める」「この順番で並べる」といったルールが、コードのあちこちに散らばっていて、まとまった形になっていない。AIはそれを推測で埋めるしかなく、推測がずれるとデグレになります。

だから対策は、賢いモデルを選ぶことより前に、守りたい挙動を、変更の前に見える形(テスト)にしておくことです。次の章から、その具体的な手順を見ていきます。

手順①:修正の前に「今の緑」を記録する

いちばん最初にやるのは、AIに頼むことではありません。 今あるテストを走らせて、通っている状態(緑)を確認しておくことです。地味ですが、これがリグレッション対策の土台になります。

なぜ先に走らせるかというと、「AIの修正で壊れた」と「もともと壊れていた」を切り分けるためです。修正後にテストが落ちても、それが元から落ちていたのか、AIが壊したのかが分からなければ、原因の切り分けに時間を取られます。修正前に「今ここは全部緑」と分かっていれば、修正後に赤が出た瞬間、「それはAIが巻き込んだ場所だ」とすぐ言えます。

やることはシンプルです。

この「今の緑」が、あとで壊れていないことの証拠になります。テストがそもそも無い場所を触るときは、ここで手を止めて、手順③に飛んでください。守るものが無いまま任せるのが、いちばん危ない進め方です。

手順②:不変条件と既存テストを一緒に渡す

「今の緑」を確認したら、AIに修正を頼みます。 このとき、直してほしい内容と一緒に、変えてはいけない挙動(不変条件)と、関係する既存テストを渡すのがコツです。「直して」だけでなく「これは守って」をセットにします。

頼み方の例:

次の不具合を直してください。
【直したいこと】○○のとき△△になってしまうのを、□□に直す。

ただし、次は変えないでください(リグレッション防止):
- 関数◇◇の戻り値の形(キーの名前・型)は変えない
- 例外の投げ方(どの条件でどの例外か)は変えない
- 今ある並び順・丸めのルールは維持する

参考に、この挙動を守っている既存テストを貼ります。
これらは修正後も緑のままにしてください。修正でこのテストを
書き換える必要が出たら、書き換える前に理由を説明してください。

(ここに関係する既存テストのコードを貼る)

ここで大事なのが最後の一文——「テストを書き換える前に理由を説明して」です。 リグレッションが一番たちが悪い形で紛れ込むのは、AIが自分の修正に合わせて既存テストのほうを書き換えてしまうときです。テストが緑になっていても、それはテストを緩めた結果かもしれない。「テストは原則そのまま、変えるなら申告」というルールを先に渡しておくと、この抜け道をふさげます。

不変条件は、思いつく全部でなくて大丈夫です。「これが変わったら困る」の上位3つ——たいていは戻り値の形・エラーの扱い・お金や件数の計算ルール——を渡すだけで、巻き込み事故はかなり減ります。守りたい所を言葉にするこの一手間が、AIのブレーキになります。

手順③:テストが無い場所は「今の動き」を先に固める

やっかいなのは、守りたいのにテストが無い場所を触らせるときです。 既存テストが無ければ、AIの修正が既存の挙動を壊しても、それを教えてくれるものがありません。ここは、いきなり修正を頼まず、先に「今の動き」をテストで固めてから任せます。

順番はこうです。

  1. 今の挙動を、変える前にテストにする。正しいかどうかは一旦置いて、「今こう動いている」を写し取るテスト(俗にキャラクタライゼーションテストと呼ばれます=現状の振る舞いをそのまま記録するテスト)を作る。これはAIに頼んでも構いません。「この関数の"現在の"入出力を、そのままテストにして」と頼めば、たたき台が出ます。
  2. そのテストが今、緑であることを確認する。現状を写したのだから緑になるはず。ならなければ、写し取りがずれています。
  3. 緑を確認してから、修正を頼む。手順②と同じく「このテストは緑のままで」と渡す。修正後にそのテストが落ちたら、それが挙動の変化——つまり守りたかった動きが変わったサインです。

「正しさは分からないけど、今こう動いている」を先に固定する。これだけで、変わったことに気づける状態になります。全部の関数にやる必要はありません。今回触る所と、その隣の「壊れたら痛い所」だけで十分です。壊れて困る範囲を先に囲ってから任せる、という順番が肝心です。安全に触る範囲の切り方全般は関数1個から始めるAIコーディングの安全なスコープ設計にも整理しています。

手順④:戻ってきたら、まず全テストを流して差分を見る

AIから修正が返ってきたら、コードを読み込む前に、まず機械的な確認を2つします。感覚で「大丈夫そう」と判断する前に、事実を先に取ります。

確認1:既存テストを全部流す(緑が緑のままか)

手順①で記録した「今の緑」が、修正後も緑のままかを見ます。落ちたテストがあれば、それが巻き込み事故の場所です。新しく赤になったテストの名前を見れば、どの機能を壊したかがそのまま分かります。ここで落ちが出たら、その落ちたテスト名をAIに伝えて「このテストが落ちた。挙動を変えずに直して」と返します。

確認2:テストコード自体の差分を見る(テストが書き換えられていないか)

意外と見落とすのが、テストファイルの変更です。修正の差分に、既存テストの書き換え・削除が混ざっていないか。もし既存テストが変わっていたら、それは要注意——「テストを直したから緑になった」可能性があります。テストの変更は1行ずつ、なぜ変えたのかを確認します。正当な理由(仕様が実際に変わった)ならOK、そうでなければ元に戻します。

この2つは、どちらもテストの本数や見た目の緑・赤ではなく、「何が変わったか」を見る確認です。差分の読み方全般はリファクタリングをAIに任せるときの差分の確認方法に、テストそのものを信用しすぎない構えは生成された単体テストを信用しすぎないための確認ポイントにまとめています。緑になった、で安心せず、緑になった理由まで見る。これがリグレッションを最後に食い止める一線です。

ありがちな落とし穴と、その回避

AIの修正でデグレを防ぐとき、つまずきやすい所を先に潰しておきます。

落とし穴の多くは、「守りたい挙動が、頭の中にはあるのにコードの外に出ていない」所から生まれます。 守りたい動きを、変更の前にテストという見える形にしておく。この順番さえ守れば、AIに任せる範囲を広げても、足元が崩れにくくなります。

明日からやること(小さく始める3つ)

いきなり全部を仕組み化しなくて大丈夫です。まずこの3つから。

  1. 次にAIへ修正を頼む前に、関係範囲のテストを一度流して「今の緑」を確認する:壊したのか元からかを、あとで切り分けられるようにしておきます。
  2. 頼むとき、「この挙動は変えないで/このテストは緑のままで」を一文足す:守りたい上位3つ(戻り値の形・例外・計算ルール)だけでも効きます。
  3. 戻ってきたら、テストファイルの差分を見て、既存テストが書き換えられていないか確認する:緑になった理由まで見る癖をつけます。

この3つだけでも、「AIに直させると何が壊れるか分からない」という不安が、少し扱えるものに変わります。

コピーして使う「リグレッション防止の文脈渡しシート」

AIに修正を頼む前後で、上から順に使ってください。一度に全部でなく、壊れたら痛い所だけでも十分です。

# リグレッション防止・文脈渡し

## 頼む前:今の状態を固める
- [ ] 関係範囲の既存テストを流して「今の緑」を確認した
- [ ] もともと落ちているテストは別問題としてメモした
- [ ] テストが無い場所は、今の動きを写すテストを先に作った

## 頼み方:守るものを一緒に渡す
- [ ] 直したいことを1つに絞って書いた
- [ ] 変えてはいけない挙動(上位3つ)を渡した
      例:戻り値の形 / 例外の投げ方 / 並び順・丸めのルール
- [ ] 関係する既存テストを貼り「緑のままで」と伝えた
- [ ] 「既存テストを書き換えるなら、先に理由を説明して」と伝えた

## 戻ってきたら:緑になった"理由"まで見る
- [ ] 既存テストを全部流し、緑が緑のままか確認した
- [ ] 新しく赤になったテスト名から、壊した機能を特定した
- [ ] テストファイルの差分を見て、書き換え・削除が無いか確認した
- [ ] 触る範囲を広げる前に、この範囲の緑を確定させた

リグレッション防止の前後チェックリスト

修正を頼むときと、受け取ったときに、さっと確認します。全部に○が要るわけではなく、関係する所だけで十分です。

頼むとき

受け取ったとき

最後に

AIに修正を任せたあと、「直したい所は直ったけど、他が壊れていないだろうか」と不安になる。 その不安は、むしろ品質を守る側に立っている証拠です。リグレッションが怖くて任せきれないのは、あなたが慎重だからではなく、守りたい挙動が、まだコードの外に見える形で置かれていないからです。そこをテストで固めれば、怖さはだいぶ小さくなります。

既存の挙動が壊れていないことをテストで確認でき、安心してAIに任せられるようになった開発者の穏やかな表情

一度に完璧な防御を目指さなくて大丈夫です。今日ひとつ、「修正の前に、今の緑を確認する」だけ試してみる。それだけで、AIの修正が「何を壊すか分からないもの」から、「壊れたらすぐ気づけるもの」に一歩近づきます。守りたい動きを先に見える形にしておく。その一手さえ持てば、AIに任せる範囲を広げても、足元が崩れることはありません。

よければ、こちらも

関連用語