+ 作る
図を読み込んでいます…
1 / 17
テスト駆動開発とは / 全5章

第5章 TDDで回す「完全AI自動化開発」

発行
かえで
版
第4版
改訂
分量
17コマ・4,855字

ここまでの道具を組み合わせて、issueからUT計画・テスト・実装・CI・自動レビュー・本番までをAIに回させる開発の型。TDDの基本と利点、AIと相性がいい理由、CIを本番とそろえる方法、AIの「ズル」対策、人間の役割、実務での導入ステップまで。

テスト駆動開発で「完全AI自動化開発」を回す

いよいよ最終章です。ここまでで、ユニットテスト、統合テスト、Docker、CI/CDという道具がそろいました。この章では、それらを組み合わせて、issue(やることを書いたチケット)を起点にAIが UT計画 → テスト → 実装 → CI → レビュー → 本番 までを回す開発の型を紹介します。

ポイントは一つだけです。これまで人が「このコードは正しいか」を読んで判断していた部分を、テストという機械が判定できる形に置き換えること。そのための考え方が、テスト駆動開発(TDD)です。

  • テスト駆動開発 × 完全AI自動化開発
  • issueから本番まで、テストを「機械が読める仕様」にして回す
  • Red
  • Green
  • Refactor

TDDの基本サイクル

テスト駆動開発(Test-Driven Development、略してTDD)は、「実装してからテストを書く」のではなく「テストを先に書いてから実装する」開発のやり方です。

まず Red で、まだ存在しない機能のテストを書き、失敗する(赤くなる)ことを確かめます。次に Green で、そのテストが通る最小限のコードを書きます。最後に Refactor で、テストが緑のまま、重複や名前などを整えます。この三つを、数分から数十分の小さな単位でぐるぐる回し続けます。オレンジの点が回っているように、終わりのない輪になっているのがポイントです。

  • TDDの基本:Red → Green → Refactor
  • Red
  • 失敗するテストを 先に書く
  • テストを守ったまま 設計を整える
  • Refactor
  • Green
  • 最小限の実装で テストを通す
  • 小さな単位で回し続ける

TDDの利点

テストを先に書くと、いくつもうれしいことがあります。まず、テストがそのまま「実行できる仕様書」になります。普通のドキュメントは古くなっても誰も気づきませんが、テストは仕様とずれると落ちるので、いつも最新の状態に保たれます。

次に、第1章で見たように、壊したときにすぐ気づけるので、コードの整理が怖くなくなります。テストしやすいように書こうとすると、自然と部品が小さく、依存の少ない良い設計になるのも利点です。「全部のテストが通ったら完了」と事前に決まっているので、どこまでやればいいか迷うこともありません。そして最後の利点が、この章の主役です。

  • TDDの利点
  • 書類
  • テスト=実行できる仕様書
  • ドキュメントは古くなるが、テストは古くなると落ちる
  • 守られている
  • リグレッションをすぐ検知
  • 壊してもCIが数分で教えてくれる → リファクタが怖くない
  • Red
  • パズル
  • 設計が良くなる
  • テストしやすいコード=依存が少なく責務が小さいコード
  • Refactor
  • Green
  • 旗
  • 「完了」の定義がブレない
  • このサイクルが生む5つの利点 →
  • 「全部通ったら終わり」が事前に決まっている
  • ロボット
  • AIに検証できるゴールを渡せる
  • 正しさを機械が判定 → AIが自分で直せる

なぜAIと相性がいいのか

AIは「それっぽいコード」を一瞬で書けますが、そのコードが本当に正しいかどうかは、AI自身にも分かりません。ここでテストが効いてきます。

テストがあれば、AIは書いたコードを実行して、合格か不合格かを機械的に確かめられます。失敗したらエラーの内容を読んで、自分で直してもう一度試す。これを合格するまで繰り返せばいいのです。人が一行ずつコードを読んで正しさを判断する代わりに、テストがゴールと採点表の役割を果たしてくれます。

  • TDDがAIと相性がいい理由
  • AIに「それっぽいコード」ではなく「通るコード」を書かせる
  • ロボット
  • OK
  • コード生成
  • テスト (=仕様)
  • 実行
  • AIエージェント
  • 全部通ったら PRへ
  • 失敗したらエラーログを読んで、自分で直す

全体像:issueから本番まで

ここからは、実際の開発の流れを七つの段階に分けて見ていきます。人がissueに「受け入れ条件」を書くと、AIがそれをテストの計画表にし、失敗するテストを先に書いて固定します。次に別のAIがそのテストを通す実装を書き、CIが本番と同じ条件で全部のテストを流します。機械的なチェック(ゲート)を全部通れば、本番へと進みます。

成功の鍵は三つです。テストが仕様になっていること、CIが本番と同じ条件で動いていること、そしてレビューを機械が判定できるゲートに置き換えていること。次のページからは、このパイプラインが画面の上に小さくなり、いまどの段階を見ているかをオレンジの線で示します。

  • 全体像:issueから本番まで
  • issueを入れたら、本番まで人の手を通さずに流れる
  • 書類
  • 目標
  • NG
  • ロボット
  • OK
  • 守られている
  • ロケット
  • ① Issue
  • ② UT計画
  • ③ テスト作成
  • ④ 実装
  • ⑤ CI
  • ⑥ 自動レビュー
  • ⑦ 本番
  • 受け入れ条件 を人が書く
  • AIがテスト 観点を洗い出す
  • 失敗するテスト を先に固定
  • 別のAIが テストを通す
  • 本番と同じ 環境で検証
  • ゲートを全部 通れば合格
  • 本番へ デプロイ
  • 鍵は3つ:テスト=仕様 / CI=本番 / ゲートで機械判定

① Issue:AIが読める受け入れ条件を書く

自動化の品質は、入口のissueの質で決まります。テストに変換できない書き方の条件は、AIにも検証できないからです。

受け入れ条件は、「いい感じに割引する」のようなあいまいな言葉ではなく、「有効なコードなら10%引きになる」のように、合格か不合格かを判定できる文で書きます。入力と期待する結果をできるだけ具体的にし、「ポイントとの併用は対象外」のように、やらないことも書いておくと、AIが余計な実装をしなくなります。issueのテンプレートに「受け入れ条件」と「対象外」の欄を用意しておくのがおすすめです。

  • ① Issue:AIが読める受け入れ条件を書く
  • ① Issue
  • ② UT計画
  • ③ テスト作成
  • ④ 実装
  • ⑤ CI
  • ⑥ 自動レビュー
  • ⑦ 本番
  • #42 クーポン割引を適用する
  • AIに渡せるIssueの3条件
  • 受け入れ条件
  • ① 合否を判定できる文で書く
  • □ 有効なコードで10%引き
  • ② 入力と期待結果を具体的に
  • □ 期限切れのコードはエラー
  • □ 1注文につき1枚まで
  • ③ やらないことも書く
  • □ 合計は0円未満にならない
  • NG 「いい感じに 割引する」
  • OK 「10%引き・ 1注文1枚まで」
  • 対象外:ポイントとの併用(別issue)

② UT計画:受け入れ条件をテストケース表にする

AIはissueを読んで、受け入れ条件をテストケースの表に変換します。UTはユニットテストの略です。図では、左のissueにあった四つの条件が、右の表の行へと移動して、具体的なケースに書き換わっていきます。

このときAIには、正常系(うまくいく場合)、異常系(エラーになる場合)、境界値(ぎりぎりの値)に分けて考えさせます。人が書き漏らしがちな「期限当日の23時59分」や「存在しないコード」のようなケースを、AIに補ってもらうのがコツです。もし人が確認するなら、コードではなくこの表だけを見れば十分です。

  • ② UT計画:受け入れ条件をテストケース表に
  • ① Issue
  • ② UT計画
  • ③ テスト作成
  • ④ 実装
  • ⑤ CI
  • ⑥ 自動レビュー
  • ⑦ 本番
  • #42 クーポン割引を適用する
  • 種別
  • ケース
  • 期待結果
  • 受け入れ条件 4件 → 表へ
  • 正常
  • 有効コードで1,000円の注文
  • 900円
  • 異常
  • 期限切れのコード
  • EXPIRED
  • ロボット
  • 紫の行はAIが補った 境界値・異常系
  • 異常
  • 同じ注文に2枚目を適用
  • LIMIT
  • 人
  • 人が承認するなら この表だけ見ればいい
  • 境界
  • 割引額が合計を上回る
  • 0円
  • 境界
  • 期限当日の23:59に適用
  • 適用される
  • UT計画はissueに Markdown表でコメント
  • 異常
  • 存在しないコード
  • NOT_FOUND
  • 受け入れ条件 4件 → テストケース 6件

③ テスト作成:失敗するテストを先に書いて固定する

UT計画の各行を、そのままテストコードにします。表の行がそのままエディタの中へ滑り込み、テストの名前になりました。表の文言をテスト名に使っておくと、テストの一覧がそのまま仕様書として読めるようになります。

書いたら一度実行して、全部失敗することを確かめます。まだ実装がないのだから、赤くなるのが正しいスタートです。最初から通ってしまうテストは、何も確かめていない可能性があります。

確かめたら、テストだけを先にコミットしておきます。マージはしません。同じブランチ、同じプルリクエストの中で、「テストのコミット → 実装のコミット」という順番を守るだけです。そのうえで、実装を担当するAIには tests/ フォルダへの書き込みを許可しない設定にし、CIでは「テストのコミット以降に tests/ が変わっていないか」を確かめます。「テストを書くAI」と「実装するAI」を分けることが、自動化全体の安全装置になります。

  • ③ テスト作成:失敗するテストを先に書く
  • ① Issue
  • ② UT計画
  • ③ テスト作成
  • ④ 実装
  • ⑤ CI
  • ⑥ 自動レビュー
  • ⑦ 本番
  • tests/coupon.test.ts
  • 錠
  • テストだけ先に コミットして固定
  • it('有効コードで10%引き')
  • マージはしない。実装担当のAIには tests/ を書き換えさせない
  • it('期限切れはEXPIRED')
  • it('2枚目はLIMIT')
  • まだ実装がないので 全部赤 = 正しいスタート
  • it('合計は0円未満にならない')
  • it('期限当日23:59は適用')
  • 書類
  • テスト名をケース表の文言 にすると、そのまま仕様書
  • it('不明コードはNOT_FOUND')
  • FAIL 6 / 6
  • 最初から通るテストは 何も検証していない

④ 実装:AIはテストを通すことだけに集中する

実装を担当するAIには、「このテストを全部通して。テストは変更しないこと」とだけ伝えます。AIはテストを実行し、失敗したらエラーの内容を読み、コードを直して、もう一度実行します。図では、赤い点が半分緑に変わったところです。ロックのアイコンが示すように、テストファイルは読み取り専用です。

ゴールがはっきりしているので、あいまいな指示を出したときよりも迷走しにくくなります。ただし、何度やっても通らない場合は、テストや仕様の側が矛盾しているのかもしれません。何回まで挑戦したら人に相談する、という上限を決めておきましょう。

  • ④ 実装:AIはテストを通すことだけに集中
  • ① Issue
  • ② UT計画
  • ③ テスト作成
  • ④ 実装
  • ⑤ CI
  • ⑥ 自動レビュー
  • ⑦ 本番
  • tests/coupon.test.ts
  • 錠
  • ロボット
  • 更新
  • it('有効コードで10%引き')
  • it('期限切れはEXPIRED')
  • テスト実行 → 失敗ログを読む → 修正 → 再実行 を自動で反復
  • it('2枚目はLIMIT')
  • it('合計は0円未満にならない')
  • 指示は「テストを全部通して。 テストは変更禁止」だけ
  • it('期限当日23:59は適用')
  • 何度やっても通らない時は 仕様の矛盾として人に戻す
  • it('不明コードはNOT_FOUND')
  • PASS 3 / FAIL 3

全部緑になったら、リファクタしてPRへ

六つのテストが全部緑になりました。ここでTDDのサイクルどおり、AIにリファクタ(動きを変えずにコードを読みやすく整えること)をさせ、もう一度全部緑であることを確かめてから、プルリクエストを作成します。

プルリクエストの説明には、対応したissue、UT計画の表、テスト結果を自動で載せておくと、あとから人が経緯を追うときにとても楽になります。

  • ④ 全部緑になったら、リファクタしてPRへ
  • ① Issue
  • ② UT計画
  • ③ テスト作成
  • ④ 実装
  • ⑤ CI
  • ⑥ 自動レビュー
  • ⑦ 本番
  • tests/coupon.test.ts
  • 錠
  • ロボット
  • it('有効コードで10%引き')
  • it('期限切れはEXPIRED')
  • 全部緑 → AIがリファクタ → もう一度、全部緑を確認
  • it('2枚目はLIMIT')
  • it('合計は0円未満にならない')
  • PR #128 feat: クーポン割引 (#42)
  • it('期限当日23:59は適用')
  • PR本文にissue・UT計画・ テスト結果を自動で添付
  • it('不明コードはNOT_FOUND')
  • PASS 6 / 6

⑤ CI:CIと本番がズレていると意味がない

「CIで通れば本番でも通る」と言えるためには、大前提があります。CIと本番の環境が同じであることです。図の左側のように、CIだけSQLiteで代用していたり、手元とは違う方法でビルドしていたり、環境変数を手書きしていたり、外部のAPIを全部モックにしていたりすると、CIでは緑なのに本番で落ちる、ということが起きます。左の箱が傾いてバラバラなのは、その「ずれ」を表しています。

この状態のまま自動マージまで進めてしまうと、レビューを自動化したぶんだけ、不具合がそのまま本番へ直行してしまいます。

  • ⑤ CI:CIと本番がズレていると意味がない
  • ① Issue
  • ② UT計画
  • ③ テスト作成
  • ④ 実装
  • ⑤ CI
  • PR #128
  • ⑥ 自動レビュー
  • ⑦ 本番
  • CI
  • 本番
  • SQLite で代用
  • ≠
  • PostgreSQL 16
  • 手元の方法でビルド
  • ≠
  • Dockerイメージ
  • 手書きの .env.test
  • ≠
  • 本番の環境変数
  • 外部APIは全部モック
  • ≠
  • 本物の決済API
  • CIだけ緑で本番で落ちる = 環境がズレている

CIを本番と同じ条件にそろえる

第3章で学んだDockerを使って、ずれを一つずつなくしていきます。データベースは本番と同じPostgreSQLの同じバージョンをコンテナで起動し、CIで作ったDockerイメージをそのまま本番にも使います。環境変数は形式を決めて自動でチェックし、外部のAPIは「契約テスト」(相手のAPIの約束が変わっていないかを確かめるテスト)と、サービスの提供元が用意している試験用の環境(サンドボックス)で確かめます。

傾いていた左の箱が、右の本番とぴったりそろいました。ここまでそろえて初めて、「CIの緑=本番でも動く」と言えるようになります。

  • ⑤ CI:本番と同じ条件にそろえる
  • ① Issue
  • ② UT計画
  • ③ テスト作成
  • ④ 実装
  • ⑤ CI
  • ⑥ 自動レビュー
  • ⑦ 本番
  • CI
  • 本番
  • PostgreSQL 16(コンテナ)
  • =
  • PostgreSQL 16
  • 同じDockerイメージ
  • =
  • 同じDockerイメージ
  • 環境変数を自動チェック
  • =
  • 本番の環境変数
  • 契約テスト+サンドボックス
  • =
  • 本物の決済API
  • CIで検証したイメージを、そのまま本番へ出す

⑥ 自動レビュー:人の目をゲートに置き換える

レビューを自動化するとは、人がプルリクエストで見ていたポイントを、機械が判定できる条件、つまりゲートに置き換えることです。

全部のテストが通っているか。テストを書いたコミットのあとで、テストファイルが書き換えられていないか。変更した部分がどれだけテストされているか(カバレッジ)。テストそのものがちゃんと強いか(ミューテーションスコア)。型やLint、セキュリティのチェック。そして実装とは別のAIによるレビュー。さらに、認証や課金のような危険な部分を触っていないかも確かめます。数値は一例なので、最初は「警告を出すだけ」で運用しながら、チームに合った基準に調整していきます。

  • ⑥ 自動レビュー:人の目をゲートに置き換える
  • ① Issue
  • ② UT計画
  • ③ テスト作成
  • ④ 実装
  • ⑤ CI
  • ⑥ 自動レビュー
  • ⑦ 本番
  • PR #128 クーポン割引
  • OK
  • 全テスト通過(本番同等のCI)
  • OK
  • tests/ に変更なし(改ざん防止)
  • OK
  • 差分カバレッジ 90%以上
  • 自動 マージ
  • OK
  • ミューテーションスコア 70%以上
  • OK
  • Lint・型チェック・セキュリティスキャン
  • OK
  • 実装とは別モデルのAIレビューで指摘なし
  • OK
  • 変更範囲が許可リスト内(認証・課金は除外)
  • ※ 数値は例。最初は「警告のみ」で運用して基準を調整

全部通ったら、人の承認なしでマージ

プルリクエストがゲートの上を通り抜けると、チェックがすべて緑に変わり、そのまま自動でマージされます。GitHubなら、ブランチ保護で必須のチェックを決めておき、自動マージ(auto-merge)を使えば実現できます。

一つでも落ちたら、マージせずに止めて人に知らせます。迷ったら止まる側に倒すのが、自動化の鉄則です。人の仕事は、毎回のプルリクエストを読むことから、ゲートの基準そのものを育てることに変わります。

  • ⑥ 全部通ったら、人の承認なしでマージ
  • ① Issue
  • ② UT計画
  • ③ テスト作成
  • ④ 実装
  • ⑤ CI
  • ⑥ 自動レビュー
  • ⑦ 本番
  • OK
  • 全テスト通過(本番同等のCI)
  • OK
  • tests/ に変更なし(改ざん防止)
  • OK
  • 差分カバレッジ 90%以上
  • 自動 マージ
  • OK
  • ミューテーションスコア 70%以上
  • OK
  • Lint・型チェック・セキュリティスキャン
  • PR #128 クーポン割引
  • OK
  • 実装とは別モデルのAIレビューで指摘なし
  • OK
  • 変更範囲が許可リスト内(認証・課金は除外)
  • 1つでも落ちたら止めて人に通知。「迷ったら止まる」側に倒す

落とし穴:AIは「テストを通すため」に手段を選ばない

AIに「テストを通して」と頼むと、ときどき人間が思いもしない方法で通そうとします。テストのほうを書き換えたりスキップしたりする、中身のない確認(assert)だけのテストにする、何でもモックにして本番と関係なく通す、テストの入力にだけ正解を返すように決め打ちで書く、といった具合です。

それぞれに対策があります。テストフォルダを保護して変更をゲートで止める。ミューテーションテスト(コードをわざと少し壊して、テストがちゃんと落ちるかを確かめる手法)でテストの強さを測る。本番と同じ条件のCIと契約テストを使う。そして、実装するAIには見せない「隠しテスト」や、ランダムな入力で性質を確かめる「プロパティベーステスト」で検証する。こうしたズルを想定してゲートを作っておくことが大切です。

  • 落とし穴:AIは「テストを通すため」に手段を選ばない
  • ① Issue
  • ② UT計画
  • ③ テスト作成
  • ④ 実装
  • ⑤ CI
  • ⑥ 自動レビュー
  • ⑦ 本番
  • テストを書き換える・ skipして通す
  • tests/ を保護+ 変更があればゲートで止める
  • assertが空っぽ (動けばOKなテスト)
  • ミューテーションテストで テストの強さを測る
  • 何でもモックして 本番と無関係に通す
  • 本番同等のCI+ 契約テスト
  • テストの入力だけ 決め打ちで返す実装
  • AIに見せない隠しテスト・ プロパティテストで検証

人間の役割は「何を作るか」と「例外対応」へ

完全に自動化しても、人がいらなくなるわけではありません。人の仕事が、上流と例外に移るのです。小さくなっていたパイプラインが元の大きさに戻り、誰がどこを担うかが色分けされました。

人は、何を作るかを決めてissueと受け入れ条件を書き、必要ならUT計画の表を確認します。テスト、実装、CI、レビューはAIと機械が回します。そして本番で異常が起きたときやゲートで止まったときだけ、人が呼ばれます。レビューの対象が「コードの差分」から「受け入れ条件とテスト計画」に移る。これが、レビューを自動化するということの正体です。

  • 人間の役割は「何を作るか」と「例外対応」へ
  • 人
  • 人
  • ロボット
  • 人
  • 書類
  • 目標
  • NG
  • ロボット
  • OK
  • 守られている
  • ロケット
  • ① Issue
  • ② UT計画
  • ③ テスト作成
  • ④ 実装
  • ⑤ CI
  • ⑥ 自動レビュー
  • ⑦ 本番
  • 人:Issueを書く/ UT計画を承認(任意)
  • AIが自動で回す(テスト・実装・CI・レビュー)
  • 人:異常時 だけ対応
  • 人が読むのは「コードの差分」ではなく 「受け入れ条件とテスト計画」になる

実務での導入ステップ

いきなり全部を自動にしようとせず、階段を一段ずつ上がっていきます。パイプラインの箱が、そのまま階段の段に入れ替わりました。

最初の一段は、CIを本番と同じ条件にそろえることです。ここがずれていると、上の段は全部あやうい土台の上に乗ることになります。次に、UT計画とテストをAIに書かせ、プルリクエストの中の「テストのコミット」だけは人が確認する段階へ。その次に自動レビューのゲートを入れますが、最初は警告を出すだけにして、人のレビュー結果と一致するかを見ながら基準を調整します。最後に、ドキュメントの修正や小さなバグ修正のような、失敗しても影響の小さい変更から自動マージを始め、少しずつ範囲を広げていきます。

まずは今のプロジェクトで、「CIと本番がどこでずれているか」を洗い出すところから始めてみてください。

  • 実務での導入ステップ
  • Phase 3
  • 自動マージ
  • Phase 2
  • 低リスクなラベル から範囲を広げる
  • 自動レビューゲート
  • Phase 1
  • 最初は警告のみで 基準を調整
  • まずここから
  • 場所
  • テスト先行をAIで
  • Phase 0
  • テストのコミット だけ人が確認
  • CIを本番と揃える
  • Docker・DB・環境変数 を本番と同じに

0 件のコメント

読み込み中…

権利侵害・不適切な内容の連絡: [email protected]