AI時代ほど、仕様を固定化するテストコードが重要になる

最近「AIがコードを書くならテストコードはいらないのでは?」という話を見ました。 自分も最初は「確かにそうかもしれない」と思い、最近どうやってテストコードを書いていたっけ?を思い返してみました。 そういう主張をきっかけに、無意識に自分の中で詰まっていた前提に気づかされることがありました。

このページではそれを残しておこうと思います。 ※ここで言っているのは「テスト」ではなく、機械で検証するためのテストコードの話です。テストコードを書かない前提の話ではありません。

「テストコード不要」について、「確かにそうかもしれない」と思った理由

テストコード不要が成立しているように見えるのは、だいたい次のような前提が満たされている時です。

  • 仕様がはっきりしている
  • AIが仕様通りに実装する
  • AIが仕様通りにテストコードを書く
  • それで十分に検証できる

こう並べると、一見筋は通っています。 実際、自分も「確かにそうかもしれない」と思いました。

落とし穴は「仕様を誰が担保するか」です

前提を分解すると、最後に残るの「仕様を誰が担保しているのでしょうか?」という問題です。

この手の問題はAI以前にもあって、もう17-8年前くらいでしょうか、昔帳票システムのテストでこういうことがありました。

その帳票システムでは、テスト仕様書が「作った帳票」から自動生成されていました。 自分はそのテストには関与していなかったのですが、現地のリリースに同行してテストすると、ことごとく想定と異なる帳票が出てきました。

どうしてこの状態でOKになっているのかを聞いたら、「自動生成された仕様書に沿ってテストしてOKにした」と言われました。

ただ、その仕様書を生成する元の帳票の正しさは検証されていませんでした。

間違ったものを元に仕様書を自動生成すれば、当然その仕様書は間違ったものを正として固定します。 テストが「仕様検証」にならず、実装をなぞるだけです。

AIも同じで、仕様が怪しいままAIが実装し、AIがテストコードを書き、テストコードが通っても、仕様が間違っていれば、そのテストコードは誤りです。 AIはプロンプトとコンテキストから仕様を推測します。「推測」と「最適化されたそれっぽい解」が得意な一方、誤解も普通にします。

そして「実装を書いたAI」と「テストコードを書いたAI」が同じ前提で動くと、次のようになります。

  • 仕様ミス
  • 仕様ミスを前提にしたテストコード
  • どちらも通る

この時、「テストが通った」ことは安心材料になりません。

ここまでが仕様担保の問題です。 さらにAI時代になると、別の変化もあります。 実装変更のコストが下がるので、テストコードを「どこに投資するか(何を固定化するか)」という話が出てきます。

不要になるのはテストコードではなく“実装追従テストコード”

自分はユニットテストコードそのものが不要だとは考えていません。 例えば、料金計算や業務ルールのような仕様そのものを固定化するユニットテストコードには意味があります。

価値が下がるのは、仕様ではなく内部構造を固定してしまうタイプのテストコードです。 つまり、不要になるのはテストコードではなく、実装に寄りすぎて追従し続けるテストコードです。

ここで言う「実装追従テストコード」は、振る舞い(仕様)ではなく、内部構造(クラスや関数の分割、呼び出し順、モックの貼り方など)に依存して落ちるタイプのテストコードを指しています。

AIコーディング以前にも存在はしていて、例えば次のようなものがある認識です。

  • private関数に(リフレクション、もしくはそれ相当を使って頑張って)テストコードを書く
  • モックに呼び出し順や回数を厳密に期待する
  • 仕様では触れない内部状態をテストコードで保証する

AI時代に価値が下がるテスト(実装追従テスト)

ここからはテストコードの投資先の話です。

AIは実装を書く速度も、書き換える速度も上がります。 この時代に、実装に寄りすぎたユニットテストコードはコスト効率が悪くなりがちです。

  • 内部実装の変更に耐えない
  • 直したい場所とテストコードの破壊が直結する
  • 手間をかけたのに、仕様の保証とは別のものを保証している

AI時代に重要性が高まるテスト(仕様の固定化)

AIが実装側を増幅するなら、人間が固めるべきは仕様と契約です。 だから、少なくとも次のテストコードは前に出すべきだと考えています。

  • 受け入れテストコード(機能はこう動く、をテキストではなくコードで固定)
  • E2E/システムテストコード(ユーザ視点で完結していることを固定)
  • 契約テストコード(APIの入出力やイベント形式など、システム間の約束を固定)

要は「このプロダクトにとっての仕様」を、コードベースに書いてロックするイメージです。

仕様を固定化するテストコードの価値は、仕様担保だけではありません。 仕様さえ守れていれば内部実装を自由に変えられるため、AIによる実装の生成やリファクタリングとも相性が良くなります。

AIによって実装変更コストが下がるほど、「仕様は固定しつつ実装は自由に変えられる」状態の価値は大きくなると考えています。

これは以前書いたAIで増えるのは「実装速度」ではなく「設計試行回数」だった の話とも繋がっています。

設計を何度も試せるようになるほど、内部実装は積極的に変わります。 だからこそ、変わってよいもの(実装)と変わってはいけないもの(仕様)をテストコードで分離しておく価値が高くなります。

手順(仕様が先、テストコードの実装が後)

自分がAIコーディング時代にやりたい流れは、次です。

  1. まず人間が仕様(受け入れ条件)を決める。
  2. 仕様をテストコードとして置いて固定化する(結合〜システム相当、なるべくブラックボックス)。
  3. AIに実装させ、テストコードで満たす。

実装は変えてもいいし、仕様も合意の上で変えてもいいです。 でも 仕様と実装がずれた状態でリリースしないために、結合テスト、もしくはシステムテスト相当のテストコードが拘束として必要になります。


まとめ

自分の考えを整理した結果、AI時代になってもテストコードは必要です。

ただし、守るべき対象は変わります。

実装の内部構造を固定化するテストコードの価値は相対的に下がり、 結果として、仕様を固定化するテストコードの重要性はこれまで以上に大きくなると考えています。


終わりに

AIコーディング時代に必要なのは、AIが書いたコードを検証するためのテストコードではなく、仕様を固定化するテストコードです。

AIによって実装コストが下がるほど、人間が担保すべき価値は「仕様」に集中していきます。

その意味では、AI時代に不要になるのはテストコードではなく、実装追従のテストコードです。