はじめに
前回の【モダンWeb開発 シリーズ 第5回】では、AGENTS.md とCodex Skillsをもとに、Codexを使ってショッピングサイトを段階的に実装しました。
今回は、docs/test-cases.md を基準として、既存テストとの対応確認、不足しているテストの追加、Unit Test、Integration Testを行います。自動テスト完了後は、必要に応じて人間がブラウザから目視確認する手順も扱います。
本記事では次のように範囲を分けます。
| 工程 | 対象範囲 |
|---|---|
| ソースコードの解説 | ログイン・ユーザー登録の2機能 |
| test-cases.md確認・実装との対応確認 | 一次開発として実装した全機能 |
| 既存テストとの対応確認 | 一次開発として実装した全機能 |
| Unit / Handler / Integration Testの追加・実行 | 一次開発として実装した全機能 |
| 人間によるブラウザ目視確認 |
test-cases.md で手動確認が必要な一次開発機能 |
| 最終完了判定 | 一次開発として実装した全機能 |
第5回までの確定設計に存在しない機能を、テストのためだけに追加することはしません。
なお、本記事後半では自動テスト完了後の任意手順として、人間がブラウザで目視確認するための既存商品データの確認と、商品一覧を題材にした画面確認も扱います。これはUnit TestやIntegration Testとは別の確認であり、自動テストの代わりではありません。
この記事で分かること
- ReactからPostgreSQLまで処理を追う方法
- ログイン・ユーザー登録のコードの読み方
- Work/Codex/人間の役割分担でテスト工程を進める方法
- 第3回で作成した
docs/test-cases.mdと実装・既存テストを対応付ける方法 - テストケース、正常系・異常系・境界値の整理方法
- 既存のテストデータ準備方式をCodexに調査させ、テストコードと必要なデータをあわせて実装する方法
- テストドライバの考え方
- GoのユニットテストとHandlerテスト
- PostgreSQLを含む結合テストをCodexで作成し、Dockerへアクセスできる環境で実行する方法
- Dev Container内のCodexからUnit Test、Integration Testを順番に実行する方法
- 仕様差異をCodexで解消し、本当に判断が必要な場合だけWorkへ差し戻す方法
- 確定仕様を基準にテスト工程を収束させる方法
- FAILしたテストをデバッグ・修正したあと、該当テストと関連テストを再実行する方法
- 修正による既存機能への影響をレグレッションテスト(回帰テスト)で確認する方法
- Definition of Done(完了条件)を使って無限レビューを防ぐ方法
- REST API、Frontend、ブラウザ、DBの確認方法
- 既存の商品データを利用した、全層を通す動作確認の進め方
WorkとCodexの役割を分ける
今回のテスト工程では、ChatGPT WorkとCodexを得意な仕事で使い分けます。
-
Work: 第3回で複数の設計書を横断して読み、仕様の矛盾や不足を整理し、
docs/test-cases.mdまで含めた「設計・テスト設計」を担当 -
Codex: 第6回ではソースコードと既存テストを調査し、
docs/test-cases.mdを基準に不足するテストコードやテストデータを書き、go testを実行し、失敗したら修正する「実装・実行」を担当
作業ごとに整理すると次のようになります。
| 作業 | Work | Codex | 今回のおすすめ |
|---|---|---|---|
| 第3回での設計・テスト設計 | ◎ | ○ | 実施済み |
| 重要な設計変更時の再検討 | ◎ | ○ | 必要時のみWork |
| test-cases.mdと実装の対応確認 | ○ | ◎ | Codex |
| 現在のソースコード調査 | ○ | ◎ | Codex |
| 既存 *_test.go 調査 | ○ | ◎ | Codex |
| Goテストコード作成 | ○ | ◎ | Codex |
| Fixture・テストデータ作成 | ○ | ◎ | Codex |
| go test ./... 実行 | ○ | ◎ | Codex |
| 失敗したテストのコード修正 | ○ | ◎ | Codex |
| 修正→再テストの反復 | ○ | ◎ | Codex |
全体として、
第3回 Work → 基本設計・テスト設計・test-cases.md作成
第4回 Codex → AGENTS.md・Skillsによる実装準備
第5回 Codex → 実装・段階的検証
第6回 Codex → test-cases.mdを基準としたテスト実装・実行
人間 → 結果確認・重要な仕様判断・最終確認
という3者の分業で進めます。これは「AIに全部やらせました」ではなく、設計者と実装者を分けるような開発プロセスを、実際の工程として示すものです。
人間がCodexへ指示する箇所
本記事では、人間がCodexへ実際に入力する箇所を 「人間 → Codex 指示①〜⑩」 として番号付きで示します。
| 番号 | Codexへの指示 | 目的 |
|---|---|---|
| 指示① | 実装コードの解説 | ログイン・ユーザー登録の処理経路を確認する |
| 指示② | テストデータ準備方式の調査 | 既存Fixture・Helper・Setup / Cleanupを確認する |
| 指示③ | テスト実装時の共通条件 | 既存方式を使ってテストコードとデータを実装する |
| 指示④ | 既存テストの調査 |
test-cases.md と既存テストの対応を確認する |
| 指示⑤ | 不足ユニットテストの追加 | 不足しているUnit Testだけを追加する |
| 指示⑥ | 結合テスト環境の調査 | DB接続・Schema・Cleanup方式を確認する |
| 指示⑦ | 不足結合テストの追加 | PostgreSQLを含む不足テストだけを追加する |
| 指示⑧ | 仕様差異の処理ルール | 軽微な差異と人間判断が必要な差異を分ける |
| 指示⑨ | 動作確認前の構成確認 | Frontend→Backend→PostgreSQLの経路を確認する |
| 指示⑩ | 最終テスト実装・Fix | 前回までの成果を引き継ぎ、未完了項目を収束させる |
初回は、指示①〜⑨を順番に実行し、調査・不足テストの追加・仕様差異の整理・動作確認の準備まで段階的に進めます。
指示①〜⑨相当の作業をすでに進めている場合は「指示⑩」のみ実行します。
初めて第6回の作業を行う場合
↓
指示① → ② → ③ → …… → ⑨
↓
テスト実装・検証を段階的に進める
すでに①〜⑨相当の作業が完了している場合
↓
指示⑩だけをCodexへ入力
↓
前回までの成果を引き継ぐ
↓
未実行・未完了項目を優先
↓
最終テスト・Fix
↓
Definition of Done
つまり、指示①〜⑨は記事読者が最初から同じ工程を再現するための段階的な指示であり、指示⑩はそれまでの成果を引き継いでテスト工程を収束させるための最終指示です。
テストケースとテストコードを分ける
今回特に大事なのは、テストケース(何をテストすべきか)とテストコード(どう実装するか)を分けることです。
テストケースは第3回でWorkを使って設計し、docs/test-cases.md として確定済みです。第6回では、この確定済みのテストケースを実装・既存テストと対応付けます。
仕様
↓
何をテストすべきか
↓
test-cases.md(第3回でWork作成・人間確定)
一方、テストコードの実装・実行はCodexに任せます。
テストケース
↓
既存コードを調査
↓
*_test.go
↓
テストデータ
↓
go test
↓
失敗
↓
コード修正
↓
再テスト(Codex)
この分業により、「テスト対象の設計」と「テストの実装」が混ざらず、どちらの工程に問題があるかを切り分けやすくなります。
まず実装コードを読む
第5回まででHandler/Service/Repositoryの役割は扱っているため、ここでは構成そのものを再説明するのではなく、実装された処理を次の順番で追います。
React画面
↓
API Client
↓
HTTP Method / Path
↓
Go Handler
↓
Service
↓
Repository
↓
PostgreSQL
ポイントは、画面で操作した内容が最終的にどのAPIを通り、どのDB処理につながるかを確認することです。
1. ログイン処理を確認する
ログイン画面
↓
email / password
↓
Login API
↓
Handler
↓
Service
↓
Repository
↓
ユーザー取得
↓
Password検証
↓
Session作成
↓
Cookie
確認するポイントは次のとおりです。
- Frontendから設計どおりのRequestを送っているか
- Backendでemailとpasswordを検証しているか
- passwordを平文保存・平文比較していないか
- 認証成功後にSessionが作成されるか
- Cookie属性が設計どおりか
- 認証失敗時のStatus CodeとResponseがAPI設計と一致するか
2. ユーザー登録を確認する
ユーザー登録画面
↓
email / password
↓
Frontend Validation
↓
User Registration API
↓
Backend Validation
↓
Password Hash
↓
Repository
↓
INSERT
↓
PostgreSQL
Frontend Validationは入力ミスを早く知らせるために利用しますが、最終判定はBackendです。
設計済みのemail正規化・形式条件、passwordの8〜72 Unicodeコードポイントなどについて、FrontendとBackendで判定がずれていないか確認します。
Codexに実装コードを解説させる
人間 → Codex 指示①:実装コードの解説
実際のファイル名や関数名は完成したソースから確認させます。ソースコードの調査はCodexが得意なので、ここはCodexに任せます。
今回実装したコードを確認し、次の2機能を説明してください。
対象:
- ログイン
- ユーザー登録
各機能について、実装されている範囲で、
1. React画面
2. API Client
3. HTTP MethodとPath
4. Go Handler
5. Service
6. Repository
7. PostgreSQL
の順番で処理を追ってください。
実際のファイル名・関数名を示してください。
存在しない処理やAPIを推測しないでください。
設計書と実装が異なる場合は差異を明記してください。
この時点ではファイルを変更しないでください。
テストの種類を整理する
今回扱うテストは次のように分けます。
| 種類 | 主な確認範囲 |
|---|---|
| ユニットテスト | Validator・Serviceなど小さな単位 |
| Handlerテスト | HTTP Request/Response、Status Code |
| 結合テスト | Handler・Service・Repository・PostgreSQLの連携 |
| API動作確認 | Method・Path・Request・Response・認証 |
| Frontend検証 | lint・TypeScriptコンパイル・build |
| ブラウザ確認 | 実際の入力・画面遷移・表示・エラー |
| DB確認 | 登録結果やSessionなどの永続化結果 |
自動テストだけ、あるいはブラウザ確認だけで完成と判断するのではなく、確認対象に応じて組み合わせます。
test-cases.mdをテスト工程の基準にする
各Stepで docs/test-cases.md を参照しながら実装・検証を進めています。
第3回
設計書
↓
docs/test-cases.md
↓
第4回
AGENTS.md / Skills
↓
第5回
実装・段階的検証
↓
第6回
既存テストとの対応確認
↓
不足テスト実装
↓
自動テスト
↓
API / Browser / DB確認
↓
Definition of Done
docs/test-cases.md は一次開発として確定した全機能を対象としているため、第6回のテストも一次開発全体を対象に進めます。
test-cases.mdの内容を確認する
docs/test-cases.md には、少なくとも次の情報を含めています。
- テストケースID
- 対象機能
- テスト種別
- 前提条件
- 入力・操作
- 期待結果
- 期待するHTTP Status Code(該当する場合)
- 自動テスト/手動確認の区分
- 根拠となる設計書
この内容を作り直すのではなく、各テストケースが実装や既存テストとどのように対応しているかを確認します。
設計書とテストケースを対応させる
テストケースには、できるだけどの設計を根拠にしたテストなのかを残します。例えば次のような形です。
| ID | 機能 | 種別 | 条件 | 期待結果 | 設計根拠 |
|---|---|---|---|---|---|
| TC-LOGIN-01 | ログイン | 正常系 | 正しいemail/password | ログイン成功 | api-design.md |
| TC-LOGIN-02 | ログイン | 異常系 | password不正 | 認証失敗 | api-design.md |
| TC-USER-01 | 登録 | 正常系 | 有効なemail/password | 登録成功 | requirements.md / api-design.md |
| TC-USER-02 | 登録 | 異常系 | 登録済みemail | 409 | api-design.md |
| TC-USER-03 | 登録 | 境界値 | password 7文字 | 400 | requirements.md |
| TC-USER-04 | 登録 | 境界値 | password 8文字 | 成功 | requirements.md |
| TC-USER-05 | 登録 | 境界値 | password 72文字 | 成功 | requirements.md |
| TC-USER-06 | 登録 | 境界値 | password 73文字 | 400 | requirements.md |
実際のStatus Codeや認証・認可条件は、必ず現在の docs/ の確定仕様を基準にします。これによって、
requirements.md
api-design.md
↓
test-cases.md
↓
*_test.go
という対応関係を追いやすくなります。
正常系・異常系・境界値
テストケースは少なくとも次の3方向から確認します。
正常系
正しい入力・状態で期待どおり成功するか
異常系
不正入力・未認証・重複などを適切に拒否できるか
境界値
7 / 8 / 72 / 73 のように境界の前後で正しく判定できるか
特にValidationでは、正常値を1件確認するだけでは不十分です。第3回で作成した docs/test-cases.md に正常系・異常系・境界値が含まれていることを前提として、第6回ではそれらが実際のテストコードや手動確認へ対応しているかを確認します。
test-cases.mdと実装範囲を確認する
docs/test-cases.md を新しくレビューして確定する工程ではなく、第3回で確定した内容と第5回までの実装範囲が対応しているかを確認します。特に確認するのは次の点です。
- 一次開発として実装した全機能が
docs/test-cases.mdに対応しているか - 第5回で実装した機能とテストケースが対応しているか
- 自動テスト対象と手動確認対象が識別されているか
- コード解説対象の2機能だけに確認が偏っていないか
- 一次開発対象外の機能が混ざっていないか
- HTTP Status CodeがAPI設計と一致しているか
- DBを使う必要があるケースが識別されているか
- ブラウザで確認すべきケースが識別されているか
確定済みのtest-cases.mdをCodexへ渡す(設計者と実装者を分ける)
Workを使って作成し、人間が確認して確定した docs/test-cases.md を、Codexへ「実装・実行側の入力」として渡します。このとき、Codexにはテストケースを勝手に変更させず、実装・実行を担当させます。 設計者と実装者を分けるイメージです。
第3回で作成・確定した
docs/test-cases.md
↓
第5回までの実装
↓
Codex
↓
既存コード・テストデータ準備方式を調査
↓
不足テストを特定
↓
*_test.go と必要なテストデータを実装
↓
go test 実行
↓
失敗したら修正
↓
再テスト
Codexへ渡すときの前提として、次を明示します。
docs/test-cases.md はWorkを使って作成し、人間が確定したテスト設計です。
あなた(Codex)はこのテストケースを勝手に変更・削除・追加しないでください。
テストケースを基準として、既存コードとテストデータ準備方式の調査・
不足テストの特定・テストコードと必要なテストデータの実装・
go test 実行・失敗時の修正を担当してください。
テストケースの内容に疑問や仕様不足がある場合は、
勝手に仕様を変更せず、該当するテストケースIDとともに報告してください。
テストデータの準備方法をCodexに確認させる
確定した docs/test-cases.md をCodexへ渡したら、すぐにテストデータだけを先に作成するのではなく、まず既存のテストデータ準備方法を調査させます。
テストデータは *_test.go、Fixture、Test Helper、Setup処理と密接に関係します。そのため、先に全テストデータを作り切るのではなく、既存方式を確認したうえで、不足するテストコードを実装するときに、そのテストに必要なデータもあわせて実装する方針とします。
docs/test-cases.md
↓
既存テストをCodexが調査
↓
既存Fixture / Helper / Setupを調査
↓
不足しているテストを特定
↓
テストコードを実装
↓
そのテストに必要なテストデータを
Fixture / Helper / Setupとして実装
↓
go test
↓
失敗
↓
修正
↓
再テスト
↓
Cleanup / Rollback確認
つまり、テストデータを独立した事前工程として大量に作るのではなく、「何をテストするか」は docs/test-cases.md、「どう実装し、どのデータを使うか」は既存コードを確認したCodexという役割分担にします。
今回の開発は学習用ショッピングサイトの一次開発であり、本番環境へのデプロイや本番運用は対象としていません。 テストについても、第2回から使用している Docker Compose + Dev Container + PostgreSQLのローカル開発環境を利用します。第5回と同様に、通常のBackend接続には DATABASE_URL、Repository / Integration Testには TEST_DATABASE_URL を使用します。
Windows 11
↓
Docker Desktop
↓
Docker Compose
├─ app
│ ├─ Go
│ └─ React + TypeScript
│
└─ db
└─ PostgreSQL
↓
テスト用Schema / 一時テーブル
通常の開発データを自動テストの前提にするのではなく、既存の一時テーブル、テスト用Schema、Fixture、Setup / Cleanup処理などを利用してテストデータを分離します。
まず既存のテストデータ作成方法を確認する
人間 → Codex 指示②:テストデータ準備方式の調査
いきなり新しいFixtureやテストデータ作成処理を書かせず、現在のプロジェクトにどのような仕組みが存在するかをCodexに確認させます。この段階ではファイルを変更させません。
docs/test-cases.md のテストコードを実装する前に、
既存のテストデータ準備方法を調査してください。
確認対象:
- docs/test-cases.md
- docs/database-design.md
- docs/api-design.md
- 既存の *_test.go
- 既存のFixture / Test Helper
- Setup / Teardown処理
- DB接続設定
- DATABASE_URL
- TEST_DATABASE_URL
- .env
- compose.yml
- Cleanup / Rollback処理
確認してください。
1. 各テストケースで必要になるテストデータ
2. 現在どのようにテストデータを作成しているか
3. FixtureやTest Helperが存在するか
4. 一時テーブルやテスト用Schemaが存在するか
5. テスト終了後にデータを削除またはRollbackしているか
6. テスト間の独立性が確保されているか
7. 既存方式を利用して各テストケースのデータを準備できるか
重要:
- この時点ではファイルを変更しないでください
- 存在しないFixtureやHelperを推測しないでください
- 既存方式がある場合はそれを優先してください
- 新しいFixture、seedファイル、テストデータ用ディレクトリを作成しないでください
- 通常の開発用seedをテスト都合だけで変更しないでください
- 新しいDB、別コンテナ、別インフラを独断で追加しないでください
最後に、
- 既存方式だけで準備できるテストケース
- 既存方式の拡張が必要なテストケース
- 現在の構成では安全に準備できないテストケース
をテストケースIDとともに報告してください。
ここで確認するのは、テストデータそのものを先に完成させることではなく、テストコード実装時にどの方式でデータを準備するかです。
テストコードと必要なテストデータをあわせて実装する
既存方式を確認したら、まず不足しているUnit Testを実装し、必要なテストデータも既存のFixture / Helper / Setup方式を優先してテストコードとあわせて実装します。Unit Testを実行してすべてPASSすることを確認し、失敗した場合は原因を修正して再実行します。Unit Testが完全にPASSしたあと、Handler→Service→Repository→PostgreSQLまでを確認するIntegration Testの工程へ進み、不足している結合テストと必要なテストデータを実装します。
不足しているUnit Testを特定
↓
Unit Testを実装
↓
必要なデータを
Fixture / Helper / Setupで生成
↓
Unit Test実行
↓
FAIL → 修正 → Unit Test再実行
↓
PASS
↓
結合テスト工程へ進む
↓
不足しているIntegration Testを特定
↓
Integration Testを実装
↓
必要なデータを
Fixture / Helper / Setupで生成
↓
Integration Test実行
↓
Cleanup / Rollback
Codexへテスト実装を依頼するときは、次のルールを共通条件として加えます。
人間 → Codex 指示③:テスト実装時の共通条件
各テストに必要なテストデータは、
既存のFixture / Test Helper / Setup方式を優先して、
テストコードとあわせて実装してください。
今回は学習用ショッピングサイトの一次開発であり、
本番環境へのデプロイ・本番運用は対象としていません。
テストも、Docker Compose + Dev Container + PostgreSQLの
ローカル開発環境を使用してください。
方針:
- 必要なテストデータの具体値はテスト目的から判断してください
- 既存テスト内でデータを生成している場合は、その方式を優先してください
- 既存Fixture / Helperで管理している場合は、その仕組みを再利用してください
- PostgreSQL Integration Testでは、既存の一時テーブル・テスト用Schema・Setup処理を優先してください
- Docker Composeの既存dbサービスを利用してください
- 通常のBackend接続には第2回で設定したDATABASE_URLを使用してください
- Repository / Integration Testには第2回で設定したTEST_DATABASE_URLを使用してください
- DB接続情報をテストコードやGoのソースコードへ直接記述しないでください
- localhost:5432ではなくDocker Compose内のdb:5432を使用してください
- 通常の開発データを自動テストの前提データとして直接利用しないでください
- 自動テスト用データはテストコード、Fixture、Helper、Setup処理などから生成してください
- 新しいFixture、seedファイル、テストデータ用ディレクトリを独断で追加しないでください
- 新しい配置場所が必要な場合は、作成前に理由と配置候補を報告してください
- 通常の開発用seedをテスト都合だけで変更しないでください
- 新しい本番相当環境、別DBサーバー、別コンテナをテストのためだけに追加しないでください
- テスト間でデータを共有しないでください
- テストの実行順序に依存させないでください
- テスト終了後はCleanupまたはRollbackしてください
- 一次開発の仕様を変更しないでください
- test-cases.md のテストケースを変更しないでください
- テストのためだけに本番コードを不必要に変更しないでください
- 無関係なファイルを変更しないでください
既存のDocker Compose + PostgreSQL環境の中で
安全にテストデータを分離できない場合は、
独断でDB構成、compose.yml、ディレクトリ構成を変更せず、
該当するテストケースIDと理由を報告してください。
実装・実行後、
1. 対象テストケースID
2. 実装したテスト
3. 使用したテストデータ
4. データの作成方法
5. テストデータを定義・生成したファイル
6. 使用したDatabase / Schema / 一時テーブル
7. Cleanup / Rollback方法
8. 変更したファイル
9. 実行したコマンド
10. 成功・失敗・未実行とその理由
を報告してください。
この方式なら、テストケースごとに必要なデータがテスト実装と近い場所で管理され、不要な共通Fixtureやテスト専用seedを先回りして増やすことを避けられます。
テストデータと動作確認用サンプルデータは分ける
自動テスト用データと、ブラウザで確認するためのサンプルデータは目的が異なります。
自動テスト用データ
↓
Unit / Handler / Integration Test
↓
Cleanup / Rollback
↓
残さない
一方、後半の商品一覧の動作確認では、既存seedで登録されている商品データを利用し、Go API、React、Browserまで実際につないで確認します。
| データ | 目的 | 作成 | 終了後 |
|---|---|---|---|
| 自動テスト用データ | Unit / Handler / Integration Test | テストコードとあわせてCodexが生成 | Cleanup / Rollback |
| 動作確認用の商品データ | API / Browser / DB確認 | 既存seedの商品データを利用 | 削除しない |
この2種類を分けることで、テスト用データが開発DBへ残る、動作確認用データをIntegration Testが前提にする、テストの実行順序によって成功・失敗が変わる、といった状態を避けやすくなります。
今回の方針は、テストデータを先に独立して作り切るのではなく、既存方式を先に調査し、不足するテストコードと必要なテストデータをセットで実装するというものです。
テストケースをテストレベルへ分類する
test-cases.md のテストケースを、実際にどのレベルで確認するか整理します。
| テストレベル | 主な確認対象 |
|---|---|
| ユニットテスト | Validator、Serviceなどの小さな処理 |
| Handlerテスト | HTTP Request/Response、Status Code |
| 結合テスト | Handler→Service→Repository→PostgreSQL |
| API動作確認 | 実際に起動したREST API |
| Frontend検証 | lint、TypeScript、build |
| ブラウザ確認 | 入力、画面遷移、Loading、Error、成功状態 |
| DB確認 | 登録・更新・Sessionなどの永続化結果 |
すべてのテストケースを同じ方法で確認する必要はありません。例えばpasswordの文字数判定ならユニットテストが適しています。一方、ユーザー登録について、
HTTP Request
↓
Handler
↓
Service
↓
Repository
↓
PostgreSQL
↓
HTTP Response
まで確認する場合は結合テストになります。
テストドライバとは
テストドライバは、テスト対象を呼び出して入力を与え、結果を確認する側のコードです。例えばValidatorのテストなら *_test.go から対象関数を呼び出して入力値と期待結果を比較します。
Test Code
↓
対象関数を呼ぶ
↓
入力を与える
↓
戻り値・errorを確認
Goでは通常 *_test.go のテストコードがこの役割を担います。
ユニットテスト
本記事では、まずユニットテストを実行し、ユニットテストがPASSしてから結合テストへ進みます。 また、ユニットテストと結合テストはいずれも、第2回で構築したDev Container上で実行します。Windows側へGoやNode.jsのテスト環境を別途構築するのではなく、Docker Composeの app Containerをテスト実行環境として利用します。
Windows 11
↓
Docker Desktop
↓
Docker Compose
├─ app Container
│ ├─ Go
│ ├─ Node.js
│ ├─ Unit Test
│ ├─ Handler Test
│ └─ Frontend Test
│
└─ db Container
└─ PostgreSQL
↑
│
Integration Test
ユニットテストでは、ValidatorやServiceなどを小さい単位で確認します。Goではテーブル駆動テストを利用すると、境界値をまとめて確認しやすくなります。
tests := []struct {
name string
input string
wantErr bool
}{
{"7文字", ".......", true},
{"8文字", "........", false},
}
これは考え方を示す例です。実際の記事では、プロジェクトに存在するValidatorや関数名に合わせます。
Serviceのテストでは、RepositoryをFakeやMockへ差し替え、DBに依存しない業務ロジックを確認する方法もあります。
Handlerテスト
Goの net/http/httptest を利用すると、HTTP層をテストできます。
HTTP Request
↓
Handler
↓
HTTP Response
主に次を確認します。
- HTTP Method
- Status Code
- JSON Response
- Validation Error
- 認証・認可エラー
結合テスト
ユニットテストで小さな単位の処理を確認したあと、結合テストへ進みます。結合テストもDev Containerの app Containerから実行し、Docker Compose上の db ContainerにあるPostgreSQLへ接続します。
Unit Test
↓
PASS
↓
Integration Test
↓
Handler
↓
Service
↓
Repository
↓
PostgreSQL
この順番にすることで、ValidatorやServiceなどの単体レベルの問題を先に解消してから、DBやTransactionを含む結合部分を確認できます。ユニットテストがFAILした場合はそこで停止し、原因を修正してユニットテストを再実行します。PASSを確認してから結合テストへ進みます。
結合テストでは複数の層を実際につなげて確認します。
HTTP Request
↓
Handler
↓
Service
↓
Repository
↓
PostgreSQL
↓
HTTP Response
ユーザー登録なら、API呼び出しからValidation、password hash、DBへのINSERT、Responseまでを確認できます。
ログインなら、テストユーザーを用意し、password検証、Session作成、Cookie返却まで確認できます。
Codexに既存テストを調査させる
人間 → Codex 指示④:既存テストの調査
第3回で作成・確定した docs/test-cases.md があっても、すぐに新しい *_test.go を作らせるわけではありません。第5回までの実装ですでにテストが存在する可能性があるため、まず既存テストをCodexに調査させます。
docs/test-cases.md と現在のテストコードを比較してください。
対象:
- docs/test-cases.md に定義された一次開発の全機能・全テストケース
最初に既存の *_test.go を調査してください。
各テストケースについて、
- 実装済み
- 一部実装
- 未実装
- 自動化対象外
のどれに該当するか整理してください。
さらに、
- ユニットテスト
- Handlerテスト
- 結合テスト
- 手動確認
のどのレベルで確認されているかを整理してください。
存在しないテストを実装済みとして扱わないでください。
test-cases.md のテストケースは変更しないでください。
この時点ではファイルを変更しないでください。
最後に、不足している重要な自動テストだけを一覧で報告してください。
ここでも、
既存調査
↓
不足確認
↓
追加
の順番を守ります。
Codexにユニットテストを追加させる
人間 → Codex 指示⑤:不足ユニットテストの追加
既存テストと test-cases.md を比較したあと、不足しているユニットテストを追加します。例えばValidationでは、
7文字 → NG
8文字 → OK
72文字 → OK
73文字 → NG
のような境界値をテーブル駆動テストで確認できます。
docs/test-cases.md と既存テストの比較結果を基準として、
不足しているユニットテストだけを追加してください。
対象:
- docs/test-cases.md に定義された一次開発の全機能
- そのうちユニットテストで確認することが適切な全テストケース
要件:
- docs/の確定設計を変更しない
- test-cases.md のテストケースを変更しない
- AGENTS.mdに従う
- 既存テスト構成を優先する
- 正常系・異常系・境界値を必要な範囲で追加する
- テストのためだけに本番コードを不必要に変更しない
- 一次開発対象外の機能を追加しない
- 無関係なファイルを変更しない
実装後はbackend-verifyの手順に従って検証してください。
最後に、
- 追加したテストケースID
- 変更ファイル
- 実行したコマンド
- 成功
- 失敗
- 未実行とその理由
を報告してください。
結合テストもCodexに作成させる
Codexにはユニットテストだけでなく、Handler→Service→Repository→PostgreSQLまで実際につなぐ結合テストも作成・実行させることができます。今回のCodex CLIはDev Containerの app Container内で動作するため、テストコードの作成から実行まで同じ開発環境で進めます。
今回の環境では、
Dev Container内のCodex
↓
テストコードを作成
↓
app Container
↓
Go Test
↓
Handler
↓
Service
↓
Repository
↓
db:5432
↓
PostgreSQL
という形でテストできます。
ただし、結合テストにはユニットテストにはない注意点があります。結合テストはDBの状態に依存するため、「前のテストが残したデータが次のテストを壊す」事故が起きやすいです。だからこそ、Codexへ丸投げせず、ユニットテストと同じく 既存調査 → 不足分の追加 → 実行・報告 の工程に分けるのがポイントです。
結合テストでCodexに任せる範囲
Codexに任せやすい作業は次のとおりです。
- 既存の結合テストの調査
-
test-cases.mdとの対応確認 - 不足する結合テストの特定
-
*_test.goの作成 - Handler経由でService・Repository・PostgreSQLまで通すテスト
-
go test ./...の実行 - 成功・失敗・未実行の報告
例えばユーザー登録なら、
POST Request
↓
Handler
↓
Validation
↓
Service
↓
Password Hash
↓
Repository
↓
INSERT
↓
PostgreSQL
↓
Response
まで確認できます。
ログインなら、
テストユーザー
↓
Login API
↓
Password検証
↓
Session作成
↓
PostgreSQL
↓
Set-Cookie
までを確認できます。
結合テストで人間が決めること
一方、DBを使う結合テストでは、Codexにすべてを自由に決めさせない方が安全です。特に次の3点は先に方針を確認します。
1. どのDBを使用するか
結合テストで本番DBを使用してはいけません。また、普段使っている開発DBを無条件にテストデータで汚す構成も避けます。候補として、
テスト専用Database
または、
テスト専用Schema
などを利用できます。プロジェクトに既存のテストDB方式がある場合は、それを優先します。
2. テストデータをどう戻すか
結合テストでは、
Test A
↓
INSERT
Test B
↓
前のデータが残っている
↓
失敗
という問題が起こることがあります。そのため、
テスト開始
↓
データ準備
↓
テスト実行
↓
Rollback / Cleanup
↓
初期状態
のように、テスト間で状態が残らない仕組みが必要です。既存プロジェクトでトランザクションRollbackやテストFixtureなどの方式が決まっている場合は、その方式を優先します。
3. PostgreSQLへ接続できる環境か
今回の構成では、Dev Container内からPostgreSQLへ db:5432 で接続します。通常のBackend接続は DATABASE_URL、Repository / Integration Testは TEST_DATABASE_URL を参照します。そのため結合テストも、TEST_DATABASE_URL を利用してPostgreSQLへ到達できる環境で実行する必要があります。
結合テストの方針をCodexに調査させる
人間 → Codex 指示⑥:結合テスト環境の調査
いきなりテストDBを新設させるのではなく、まず現在の構成を調査させます。
結合テストを追加する前に、
現在のテスト環境を調査してください。
確認対象:
- compose.yml
- backendのDB接続設定
- .env
- DATABASE_URL
- TEST_DATABASE_URL
- 既存の *_test.go
- 既存の結合テスト
- テストデータ作成方法
- Cleanup / Rollback方法
確認してください。
1. 現在の結合テストがTEST_DATABASE_URLを使用しているか
2. TEST_DATABASE_URLからdb:5432へ接続可能か
3. テスト専用DBまたはSchemaが存在するか
4. テストデータをどのように準備しているか
5. テスト終了後にどのように状態を戻しているか
6. テスト間の独立性が確保されているか
この時点ではファイルを変更しないでください。
本番DBを使用する構成にはしないでください。
既存の方式がある場合は新しい方式を追加せず、
既存方式を優先してください。
調査結果と、結合テストを安全に追加できるかを報告してください。
ここで一度Codexの調査結果を確認します。
不足する結合テストをCodexに追加させる
人間 → Codex 指示⑦:不足結合テストの追加
DBの使用方法を確認できたら、実際の結合テストを追加します。
先ほど確認したテストDB・テストデータ・Cleanup方式を維持して、
docs/test-cases.mdで不足している結合テストを追加してください。
対象:
- docs/test-cases.md に定義された一次開発の全機能
- そのうち結合テストで確認することが適切な全テストケース
要件:
- Handler → Service → Repository → PostgreSQLを実際につなぐ
- docs/の確定設計を変更しない
- test-cases.md のテストケースを変更しない
- AGENTS.mdに従う
- 既存の結合テスト方式を優先する
- 本番DBを使用しない
- テスト間でデータを残さない
- テストの実行順序に依存させない
- 一次開発対象外の機能を追加しない
- テストのためだけに本番コードを不必要に複雑化しない
- 無関係なファイルを変更しない
追加後、
backend-verifyの手順に従って検証してください。
最後に、
1. 追加したテストケースID
2. Unit / Handler / Integrationの区分
3. 使用したDB
4. テストデータの準備方法
5. Cleanup / Rollback方法
6. 変更ファイル
7. 実行したコマンド
8. 成功したテスト
9. 失敗したテスト
10. 未実行のテストと理由
を報告してください。
仕様差異はまずCodexで整理する
Codexがテスト実装中に、docs/、docs/test-cases.md、実装、既存テストの間で差異を発見することがあります。ここで毎回Workへ差し戻すと、Work → 人間確認 → Codex → 再テストの往復が増え、テスト工程がなかなか収束しません。
そこで本記事では、差異を見つけたらすべて停止するのではなく、既存の確定仕様から一意に判断できる軽微な差異はCodexで解消し、本当に人間の仕様判断が必要な場合だけ停止する方針にします。
Codexが仕様差異を発見
↓
影響範囲を確認
↓
┌────┴────┐
↓ ↓
軽微な差異 重要な仕様変更
↓ ↓
Codexで整合 人間へ報告
↓ ↓
docs 必要ならWork
test-cases ↓
実装 仕様を確定
テスト ↓
↓ Codexへ戻す
再テスト
Codexで対応してよい差異
次をすべて満たす場合は、Workへ差し戻さずCodexで対応します。
- 一次開発の既存スコープ内である
- 新しい機能を追加しない
- 新しいAPIを追加しない
- DB Schemaを変更しない
- 認証・認可方式を変更しない
- セキュリティ要件を変更しない
- 外部インターフェースを大きく変更しない
- 既存の確定仕様から合理的かつ一意に判断できる
- 複数の設計案から人間が選択する必要がない
例えば、理由コードの優先順位、設計書間の軽微な表現差、test-cases.md と実装の境界条件のずれ、既存テストの期待値が確定仕様と一致していない場合などです。
この範囲では、Codexに次まで一貫して実施させます。
差異を発見
↓
確定仕様を横断確認
↓
判断根拠を確定
↓
実装・既存テストの単純な不整合を修正
↓
関連テストを実行
↓
元のテスト工程へ戻る
重要なのは、Codexが docs/test-cases.md のテスト仕様を独断で変更しないことです。確定設計から一意に判断できる単純な記載不整合が見つかった場合は、根拠と対象箇所を報告したうえで整合させます。一方、テスト条件・期待結果・Status Codeなどテスト仕様そのものの変更や、複数の設計案から選択する必要がある変更は人間へ戻します。軽微な差異を解消したら、そのたびにプロジェクト全体をWorkで再レビューするのではなく、関連範囲を再テストして元の工程へ戻します。
人間へ確認する差異
一方、次のいずれかに該当する場合はCodexで仕様を確定させません。
- 一次開発の機能追加・削除が必要
- 新しいAPIが必要
- DB Schema変更が必要
- 認証・認可方式の変更が必要
- セキュリティ要件の変更が必要
- 外部インターフェースの大きな変更が必要
- 確定済みの主要な業務ルールを変更する必要がある
- 複数の合理的な設計案があり、既存仕様から一意に判断できない
- 既存仕様同士が明確に矛盾し、どちらを正とするか判断できない
この場合だけ作業を止め、次を人間へ報告させます。
- 該当するTC-ID
- 関連設計書
- 現在の実装
- 発見した差異
- 判断が必要な理由
- 選択肢がある場合はその選択肢
人間だけで判断できる場合はその場で確定し、複数設計書を横断した再設計が必要な場合だけWorkを利用します。Workを細かな仕様差異のたびに呼び戻さないことがポイントです。
Codexへ仕様差異の処理ルールを渡す
人間 → Codex 指示⑧:仕様差異の処理ルール
テスト工程の共通ルールとして、Codexへ次を追加します。
テスト・実装中にdocs、docs/test-cases.md、実装、既存テストの間で
仕様差異を発見した場合、すべてを人間やWorkへ差し戻さないでください。
まず影響範囲を確認してください。
次をすべて満たす場合は、既存の確定仕様を基準として
Codexで差異を解消してください。
- 一次開発の既存スコープ内である
- 新しい機能を追加しない
- 新しいAPIを追加しない
- DB Schemaを変更しない
- 認証・認可方式を変更しない
- セキュリティ要件を変更しない
- 外部インターフェースを大きく変更しない
- 既存の確定仕様から合理的かつ一意に判断できる
- 複数の設計案から人間が選択する必要がない
この範囲では必要に応じて、
1. 確定仕様と差異の根拠を確認
2. 実装の単純な不整合を修正
3. 既存テストの期待値など、確定仕様から一意に判断できる不整合を修正
4. 関連テストを実行
まで一貫して行ってください。
docs/test-cases.md のテスト条件・期待結果・Status Codeなど、
テスト仕様そのものを独断で変更しないでください。
確定設計から一意に判断できる単純な記載不整合を発見した場合は、
対象箇所と判断根拠を報告してください。
設計変更になる場合は人間へ報告してください。
次のいずれかに該当する場合は、独断で仕様を決めず停止してください。
- 一次開発の機能追加・削除が必要
- 新しいAPIが必要
- DB Schema変更が必要
- 認証・認可方式の変更が必要
- セキュリティ要件の変更が必要
- 外部インターフェースの大きな変更が必要
- 確定済みの主要な業務ルールを変更する必要がある
- 複数の合理的な設計案があり、既存仕様から一意に判断できない
- 既存仕様同士が明確に矛盾し、どちらを正とするか判断できない
この場合だけ、
- 該当TC-ID
- 関連設計書
- 現在の実装
- 発見した差異
- 判断が必要な理由
- 選択肢がある場合はその選択肢
を報告してください。
Codexで軽微な差異を解消した場合は、最終報告で、
- 発見した差異
- 判断根拠
- 確認した関連docs
- docs/test-cases.mdに記載不整合があった場合は対象箇所と判断根拠
- 修正した実装
- 修正・追加したテスト
- テスト結果
を報告してください。
軽微な差異を修正するたびにプロジェクト全体を再レビューしないでください。
今回の作業範囲と関係のない改善点、リファクタリング候補、
二次開発案を新しいブロッカーとして追加しないでください。
確定仕様への適合に必要な範囲で修正し、
関連テストが成功したら元のテスト工程へ戻ってください。
このルールにより、人間が毎回差異を読み直してWorkへ指示し、結果を再びCodexへ渡す作業を減らせます。一方で、DB Schemaや認証方式など、設計判断として重要な変更は人間側に残せます。
Dev Container内のCodexでテストを実行する
第2回から第5回までの修正により、今回のCodex CLIはWindows側ではなくDev Containerの app Container内で動作します。
Windows 11
↓
Docker Desktop
↓
Docker Compose
├─ app Container
│ ├─ Go
│ ├─ Node.js
│ ├─ Codex CLI
│ ├─ Unit Test
│ └─ Integration Test
│
└─ db Container
└─ PostgreSQL
この構成では、Codex自身がGo、Node.js、プロジェクトファイルへアクセスできるため、以前のように「Windows側のCodexがテストコードを作成し、人間がDev Containerへ移ってテストコマンドを実行する」という分担は不要です。
CodexはDev Container内の /workspaces/shopping-site から起動します。
cd /workspaces/shopping-site
codex
以降のテストも、基本的にはCodexへ指示してDev Container内で実行させます。
人間
↓
Codexへテスト実装・実行を指示
↓
Dev Container内のCodex
├─ 既存テストを調査
├─ 不足テストを追加
├─ Unit Testを実行
├─ FAILがあれば必要範囲だけFix
└─ Unit Testを再実行
↓
Unit Test PASS
↓
結合テスト工程へ進む
↓
Integration Testを実行
↓
FAILがあれば必要範囲だけFix
↓
Integration Test PASS
↓
Definition of Done
重要なのは、Unit TestとIntegration Testを一度にまとめて進めず、まずUnit Testを完全にPASSさせてから結合テスト工程へ進むことです。
今回の構成では、テストを実行するためだけの scripts/unit-test.sh や scripts/integration-test.sh を必須にはしません。CodexがDev Container内で必要なコマンドを直接実行できるためです。既存の検証スクリプトがある場合は再利用できますが、記事の手順のためだけに新しいシェルスクリプトを追加する必要はありません。
Unit TestをCodexに実行させる
前述の人間 → Codex 指示⑤:不足ユニットテストの追加では、不足しているUnit Testを追加したあと、そのままDev Container内でUnit Testを実行させます。
不足しているUnit Testを追加したあと、Dev Container内でUnit Testを実行してください。
方針:
- BackendのUnit Test / Handler Testを対象としてください
- Frontend Testが存在する場合は対象に含めてください
- PostgreSQLへ接続するIntegration Testはまだ実行しないでください
- package.json に存在しないnpm scriptを勝手に追加しないでください
- 新しいテスト仕様や依存パッケージを追加しないでください
- docs/test-cases.mdを変更しないでください
- 一次開発の仕様を変更しないでください
- FAILした場合は原因を分類し、FAILに関係する範囲だけ修正してください
- 修正後は必要なUnit Testを再実行してください
Unit TestがすべてPASSしたら結果を報告し、そこで一度停止してください。
Integration Testへはまだ進まないでください。
Unit TestがFAILした場合は、結合テスト工程へ進みません。 CodexにFAILの原因を確認させ、必要な範囲だけ修正・再テストします。
Unit Test
↓
FAIL
↓
原因分類
↓
必要な範囲だけFix
↓
Unit Test再実行
↓
PASS
すべてPASSしたことを確認した時点で、ユニットテスト工程を完了とし、初めて結合テスト工程へ進みます。
Integration TestをCodexに実行させる
ユニットテスト工程が完全にPASSしたあと、前述の人間 → Codex 指示⑥:結合テスト環境の調査、人間 → Codex 指示⑦:不足結合テストの追加へ進みます。
Integration Testでは、Dev Containerの app Containerから TEST_DATABASE_URL を参照し、Docker Composeの db ContainerにあるPostgreSQLへ db:5432 で接続します。
Unit Test
↓
PASS
↓
Integration Test
↓
Handler
↓
Service
↓
Repository
↓
db:5432
↓
PostgreSQL
Codexへは次のように指示します。
Unit TestがすべてPASS済みであることを前提として、Integration Testを実行してください。
方針:
- Handler → Service → Repository → PostgreSQLを確認するIntegration Testを対象としてください
- Dev Containerのapp ContainerからTEST_DATABASE_URLを使用してdb:5432のPostgreSQLへ接続してください
- DB接続情報をテストコードへ直接記述しないでください
- Unit Test工程を最初からやり直さないでください
- 本番DBを使用しないでください
- 既存のテスト用Database / Schema / 一時テーブル / Fixture / Helper / Setup / Cleanup方式を優先してください
- テスト間でデータを残さないでください
- テストの実行順序に依存させないでください
- docs/test-cases.mdを変更しないでください
- 一次開発の仕様を変更しないでください
- FAILした場合は原因を分類し、FAILに関係する範囲だけ修正してください
- 修正後は必要なIntegration Testを再実行してください
最後に、実行したIntegration Test、使用したDatabase / Schema / 一時テーブル、テストデータの準備方法、Cleanup / Rollback方法、実行結果を報告してください。
デバッグ後は再テストとレグレッションテストを行う
テストがFAILして原因を修正した場合は、修正した時点で完了ではありません。まずFAILしたテストを再実行し、その不具合が解消したことを確認します。そのあと、修正箇所に関連する既存テストを再実行し、修正によって別の機能を壊していないことを確認します。
テスト実行
↓
FAIL
↓
原因を分類
↓
デバッグ
↓
必要な範囲だけFix
↓
FAILしたテストを再実行
↓
PASS
↓
関連テストを再実行
↓
レグレッションテスト
↓
全体検証
ここで、再テストと**レグレッションテスト(回帰テスト)**は目的が異なります。
| テスト | 目的 |
|---|---|
| 再テスト | 修正した不具合そのものが解消したか確認する |
| レグレッションテスト | 修正によって、これまで正常だった既存機能へ影響が出ていないか確認する |
例えばユーザー登録のValidationを修正した場合、まずFAILしていたユーザー登録のテストを再実行します。そこでPASSしたあと、同じValidationや認証処理に関係するHandler Test、Integration Testなどを再実行します。共通処理や広い範囲へ影響する修正であれば、Backend全体の go test ./... やFrontendの既存テスト、lint、buildも実行します。
ただし、修正のたびに無条件で全テストを最初から実行するのではなく、まず該当テスト、次に関連テストという順番で確認します。そのうえで、一次開発全体のDefinition of Doneを確認する最終段階では、必要な全体テストをレグレッションテストとして実行します。
Fix
↓
該当テスト
↓
関連テスト
↓
影響範囲に応じたレグレッションテスト
↓
最終全体検証
この流れにすることで、「修正した不具合は直ったが、別の機能が壊れた」という状態を見逃しにくくなります。
この構成では、人間がUnit TestやIntegration Testのコマンドを1件ずつ手入力する必要はありません。人間はCodexへ工程を指示し、CodexがDev Container内で実装・実行・FAIL時の修正・再テストまで行います。
人間 → Codex
↓
Unit Test実装・実行
↓
PASS
↓
人間が結果確認
↓
人間 → Codex
↓
Integration Test実装・実行
↓
PASS
↓
人間が結果確認
↓
全体検証
Codexが実行したコマンドと結果は、最終報告で確認できるようにします。
Backendテストを実行する
ここからのコマンドは、Dev Container内のCodexが実行する検証内容を個別に確認するためのものです。通常は人間が毎回すべてを手入力するのではなく、Codexへテスト工程を指示して実行させます。
Backendのテストを個別に実行する場合は次のとおりです。
cd /workspaces/shopping-site/backend
go test ./...
以前の実行では、次のように各packageのテスト成功を確認できました。
? example.com/shopping-site/backend [no test files]
ok example.com/shopping-site/backend/internal/config
ok example.com/shopping-site/backend/internal/handler
? example.com/shopping-site/backend/internal/product [no test files]
ok example.com/shopping-site/backend/internal/repository
? example.com/shopping-site/backend/internal/service [no test files]
[no test files] は失敗ではなく、そのpackageにテストファイルが存在しないことを示します。
ここで重要なのは、単に go test ./... → PASS を見るだけではありません。Codexの報告から、
TC-USER-01 → Integration Test → PASS
TC-USER-02 → Integration Test → PASS
TC-USER-03 → Unit Test → PASS
TC-USER-04 → Unit Test → PASS
のように、第3回で作成・確定した test-cases.md のケースがどのテストで確認されたのかも追跡します。これにより「テストは通ったが、必要なケースが本当にカバーされているか」まで確認できます。
失敗したテストがあれば、Codexにコードを修正させ、再テストを反復させます。この「修正→再テスト」の反復もCodexが得意な作業です。
Race Detectorも確認する
並行処理を含むBackendでは、必要に応じてRace Detectorも実行します。
cd /workspaces/shopping-site/backend
go test -race ./... -count=1
ただし、実行環境やテスト構成によって利用条件が異なるため、実行できなかった場合は「未実行」と理由を報告します。
Backendをビルドする
cd /workspaces/shopping-site/backend
go build ./...
成功時は何も表示されず、Dev Containerのターミナルへ戻ることがあります。
vscode ➜ /workspaces/shopping-site/backend (main) $
これは正常です。Windows側のPowerShellで実行するコマンドについては、該当箇所で「PowerShellで実行」と明記します。
Frontendを検証する
第5回までに作成したFrontend検証ルールに従い package.json に存在するscriptだけを実行します。現在の構成で lint と build が定義されている場合は、例えば次を実行します。
cd /workspaces/shopping-site/frontend
npm run lint
cd /workspaces/shopping-site/frontend
npm run build
build が tsc -b && vite build なら、TypeScriptのコンパイル確認も含まれます。
存在しない test や typecheck scriptを、検証のためだけに勝手に追加しません。
API単体で動作確認する
Frontendを介さずREST APIを確認すると、問題がFrontend側かBackend側かを切り分けやすくなります。
HTTP Client
↓
Go Backend
↓
PostgreSQL
確認する項目は次のとおりです。
- Method
- Path
- Request
- Response
- Status Code
- Cookie
- CSRF
- Validation Error
具体的なRequest/Responseは docs/api-design.md を基準にします。
目視確認用の商品データを確認する
ここからは、Unit TestとIntegration Testによる自動テストとは別に、必要に応じて人間がブラウザから実際の画面を操作して目視確認します。この作業は本来のUnit TestやIntegration Testの代わりではなく、自動テスト完了後に実際の画面表示や操作結果を確認したい場合に行う任意の確認です。
今回の products テーブルには、第5回までの実装で既存seedの商品データが登録されています。そのため、目視確認のためだけに新しい商品をINSERTせず、既存の商品データを利用します。
まず、Windows側のPowerShellでプロジェクトルートへ移動し、Composeの db Container内のPostgreSQLへ接続します。
cd C:\work\shopping-site
docker compose exec db psql -U appuser -d shop
ここはDev Container内のターミナルではなく、Docker Desktopを利用しているWindows側のPowerShellで実行する例です。Dev Container内から実行する場合は、Docker CLIを利用できる構成かを確認してください。
products テーブルは確定済みのDB Schemaに合わせて、price_jpy、stock、is_active などの列を使用します。price や image_url という列は存在しないため、動作確認用SQLでも使用しません。
登録済みの商品を確認します。
SELECT id, name, price_jpy, stock, is_active, description
FROM products
ORDER BY created_at, id;
商品データが表示されれば、ブラウザでの商品一覧確認にはその既存データを使用します。ここでは動作確認のためにDB Schemaやseedを変更しません。
確認できたらPostgreSQLを終了します。
\q
目視確認では既存seedの商品データを利用します。自動テスト用のFixtureやテストデータとは分けて扱い、passwordの平文や秘密情報は記事へ掲載しないよう注意します。
Codexに動作確認前の構成を確認させる
人間 → Codex 指示⑨:動作確認前の構成確認
動作確認では、商品一覧を題材にFrontendからBackend、PostgreSQLまでを通して確認します。ここでも、いきなり操作するのではなく、まず対象の構成をCodexに確認させてから進めます。
Dev Container内のVS CodeターミナルでプロジェクトルートからCodexを起動します。
cd /workspaces/shopping-site
codex
Codexへ次のように入力します。
商品一覧を題材に、FrontendからBackend、PostgreSQLまでの動作確認を行います。
まず、適用されるAGENTS.mdとSkills、
backendとfrontendの現在の構成、
compose.ymlのサービス構成を確認してください。
まだファイルは変更しないでください。
確認後、既存の商品一覧API(例: GET /api/products)と
React側の商品一覧表示が、
どのファイル・どの関数でつながっているかを説明してください。
存在しない処理やAPIを推測しないでください。
ここでCodexに、
確認
↓
経路の把握
↓
動作確認
の順番を守らせます。
第3回で作成した AGENTS.md には、推測だけで進めず既存コードや構成を確認するルールを定義しています。プロンプト側でも「まだ変更しない」と明示すると、動作確認の前提を人間がチェックできます。
商品一覧の処理経路を確認する
Codexに確認させる処理経路は、例えば次のとおりです。実際のファイル名・関数名は完成したソースから確認します。
PostgreSQL
↓
productsテーブル
backend
│
├─ DB接続
├─ Product構造体
├─ Repository
├─ Service
├─ Handler
└─ GET /api/products
frontend
│
├─ Product型
├─ API呼び出し
├─ Loading
├─ Error
└─ 商品一覧表示
backend/AGENTS.md では、
handler
service
repository
を分離するルールを設定しているため、実装がそのルールに沿っているか確認します。
また、フロントエンドでは、
Loading
Success
Error
Empty
などの状態を考慮するルールを設定しています。これらが商品一覧の実装へ反映されているかも確認します。
GoからPostgreSQLへの接続先を確認する
Dev Container構成では、GoからPostgreSQLへの接続先は、
db:5432
です。接続情報はソースコードへ直接記述せず、第2回でプロジェクトルートの .env に設定した環境変数を利用します。compose.yml から app コンテナへ渡された DATABASE_URL を通常のBackend接続で使用し、Repository / Integration Testでは TEST_DATABASE_URL を使用します。
.env
↓
compose.yml
↓
app Container
├─ DATABASE_URL
└─ TEST_DATABASE_URL
↓
db:5432
ポイントは、接続情報を compose.yml やGoのソースコードへ直接固定せず、第2回で設定した .env を引き継ぐことと、localhost:5432 ではなく、db:5432 であることです。理由は、
app Container
│
│ Docker Compose Network
▼
db Container
というコンテナ間通信だからです。
今回はローカル学習環境として、第2回で設定した .env の接続情報をそのまま使用します。第6回のテスト工程で別のDB接続情報を新しく定義したり、ユーザー名やパスワードをテストコードへ直接記述したりしません。
ここで確認するのは「実装がこの接続方針に沿っているか」です。動作確認のためにドライバや依存関係を新しく追加することはしません。採用済みのPostgreSQLドライバ(例: pgx)と
go.modの内容は、実装済みのものをそのまま確認します。
バックエンドの構成を確認する
backend/AGENTS.md のルールに従うと、商品一覧は例えば次のような構成になります。
backend
│
├─ main.go
│
├─ handler
│ └─ product_handler.go
│
├─ service
│ └─ product_service.go
│
└─ repository
└─ product_repository.go
責務は次のように分かれます。
| 層 | 主な役割 |
|---|---|
| Handler | HTTPリクエスト・レスポンス |
| Service | 商品一覧取得のユースケース・業務ロジック |
| Repository | PostgreSQLへのアクセス |
処理の流れは、
GET /api/products
↓
ProductHandler
↓
ProductService
↓
ProductRepository
↓
PostgreSQL
となります。単純な商品一覧ではServiceの処理が小さくなる場合がありますが、商品検索・在庫・価格・カテゴリ・公開状態などが増えても責務を分けやすい構成になっているか、動作確認とあわせて確認します。
商品一覧APIのレスポンスを確認する
GET /api/products へアクセスしたときは、例えば次のようなJSONが返ります。
[
{
"id": 1,
"name": "ワイヤレスマウス",
"price": 2980,
"description": "シンプルなワイヤレスマウス",
"image_url": ""
},
{
"id": 2,
"name": "メカニカルキーボード",
"price": 8980,
"description": "日本語配列のメカニカルキーボード",
"image_url": ""
}
]
フロントエンドはこのJSONを受け取り、TypeScriptの Product 型として扱います。実際のMethod・Path・Response形式は docs/api-design.md と実装を基準に確認します。
CORSを確認する
今回、React(localhost:5173)とGo(localhost:8080)とポートが異なります。ブラウザから見ると異なるOriginになるため、ReactからGo APIへ直接アクセスする構成ではCORSを考慮する必要があります。
開発環境では、http://localhost:5173 からのアクセスを許可するようバックエンドが設定されているかを確認します。
考え方は、
許可するOrigin
↓
http://localhost:5173
許可するMethod
↓
GET
です。開発用だからといって無条件にすべてのOriginを許可するのではなく、必要なOriginだけを許可する方針になっているか確認します。
バックエンドを検証する
動作確認の前に、第4回で作成した backend-verify Skillでバックエンドを検証できます。Codexへ次のように入力します。
$backend-verify を使って、現在のbackendを検証してください。
Skillには、
変更内容確認
↓
gofmt
↓
go test ./...
↓
go build ./...
↓
結果報告
という手順を定義しています。
今回Codex CLIはDev Container内で動作し、Goも同じ app Container内にあります。そのためSkillではDev Container内で、
cd /workspaces/shopping-site/backend
go test ./...
や、
cd /workspaces/shopping-site/backend
go build ./...
を直接実行できます。これにより、第4回で作成したSkillを実際の動作確認工程でも利用できます。
Go APIを起動する
バックエンドの検証が完了したら、Dev Container側のターミナルでAPIを起動します。
cd /workspaces/shopping-site/backend
go run .
ここで注意したいのは、Dev Containerを起動しただけではGo APIが自動的に起動しているとは限らないことです。docker compose ps で app Containerが Up になっていても、それだけではGo Backendが8080番ポートで待ち受けていることを意味しません。
Windows側のPowerShellからContainerの状態を確認する場合は、プロジェクトルートで次を実行します。
cd C:\work\shopping-site
docker compose ps
app と db が Up になっていることを確認したうえで、Go BackendはDev Container側のターミナルから go run . で起動します。
APIが 0.0.0.0:8080 で待ち受けるようにします。compose.yml では、
ports:
- "8080:8080"
としているため、Windows側から次のURLへアクセスできます。
http://localhost:8080/api/products
PowerShellから確認する場合は、次を実行します。
curl.exe -i http://localhost:8080/api/products
または、PowerShellの Invoke-RestMethod を使用する場合は次のように実行できます。
Invoke-RestMethod http://localhost:8080/api/products
JSONの商品一覧が返れば、PostgreSQLからGo Backendまでの経路は動作しています。
もし次のように表示された場合は、
curl: (52) Empty reply from server
8080番ポートが公開されていても、Go Backendが実際には起動していない可能性があります。まずDev Container側で go run . を実行しているターミナルを確認します。
あわせてWindows側のPowerShellからContainerログを確認する場合は、次を実行します。
docker compose logs app --tail=100
Container started だけが表示され、Go Backendの起動ログがない場合も、Dev Container自体は起動していてもGo APIは起動していない可能性があります。
このため、ブラウザで商品一覧を確認する前に、
1. db Containerが起動している
↓
2. app Containerが起動している
↓
3. Dev Container内でGo Backendを起動する
↓
4. Windows PowerShellから /api/products を確認する
↓
5. Reactを起動する
↓
6. ブラウザで確認する
の順番で確認します。
フロントエンドのProduct型を確認する
React + TypeScript側では、APIから受け取る商品の型が定義されています。例えば次のような型です。
export type Product = {
id: number
name: string
price: number
description: string
image_url: string
}
APIのJSONとTypeScriptの型を対応させます。
JSON
│
├─ id
├─ name
├─ price
├─ description
└─ image_url
↓
Product
TypeScriptを利用することで、商品データの構造がコード上で明確になっているか確認できます。
API呼び出しがコンポーネントから分離されているか確認する
第3回で作成した frontend/AGENTS.md では、API呼び出しをコンポーネントへ集中させない方針にしています。例えば、
frontend/src
│
├─ api
│ └─ products.ts
│
├─ types
│ └─ product.ts
│
└─ components
└─ ProductList.tsx
のように分離されています。役割は、
product.ts → Product型
products.ts → 商品API呼び出し
ProductList.tsx → 商品一覧UI
です。API通信・型・UIが分離されているほど、プロジェクトが大きくなったときに変更しやすくなります。実装がこの方針どおりか確認します。
API URLが環境変数へ設定されているか確認する
API URLをReactコンポーネントへ直接、fetch('http://localhost:8080/api/products') と書き続けると、環境が変わったときに修正箇所が増えます。
Viteでは、フロントエンドから利用する環境変数に VITE_ プレフィックスを付けます。例えば frontend/.env.development に、
VITE_API_BASE_URL=http://localhost:8080
を設定します。コードでは、const apiBaseUrl = import.meta.env.VITE_API_BASE_URL として利用します。
ただし、VITE_ が付いた値はブラウザ側から参照できるため、APIキーやパスワードなどの秘密情報を入れてはいけません。実装がこの方針どおりか確認します。
商品一覧の状態を確認する
商品一覧画面では、商品データだけでなく状態も確認します。
画面表示
↓
Loading
↓
API呼び出し
│
├─ 成功 + 商品あり
│ ↓
│ 商品一覧
│
├─ 成功 + 0件
│ ↓
│ Empty
│
└─ 失敗
↓
Error
例えば、
Loading → 商品を読み込んでいます...
Error → 商品の取得に失敗しました
Empty → 商品がありません
のように表示されるか確認します。これは第3回の frontend/AGENTS.md で設定したUI/UXルールが、実際の画面へ反映されているかを確認する例でもあります。
Reactを起動する
フロントエンドはDev Container側の別ターミナルで起動します。
cd /workspaces/shopping-site/frontend
npm run dev -- --host 0.0.0.0
Viteが 0.0.0.0:5173 で待ち受けることで、Windows側のブラウザから http://localhost:5173 へアクセスできます。
第2回で確認したとおり、Dev Container内だけの localhost へViteをバインドするとWindows側から正常にアクセスできないため、今回も --host 0.0.0.0 を指定します。
ブラウザで確認する
FrontendとBackendを起動し、実際の画面から確認します。Viteのポートが5173なら、例えば http://localhost:5173 へアクセスします。実際のポートはプロジェクト設定に合わせます。
今回確認する基本フローは次のとおりです。
ユーザー登録
↓
ログイン
ブラウザでは画面が表示されるだけでなく、入力・送信・Loading・エラー・成功後の状態まで確認します。
Developer ToolsのNetworkでは、URL、Method、Status、Request、Response、Cookie、Headerなどを確認します。ConsoleではJavaScript、React、CORS、API通信などのエラーがないか確認します。
ブラウザで商品一覧を確認する
あわせて、動作確認用に投入した商品が表示されるかを確認します。Windows側のブラウザで http://localhost:5173 へアクセスします。商品一覧として、
ワイヤレスマウス 2,980円 シンプルなワイヤレスマウス
メカニカルキーボード 8,980円 日本語配列のメカニカルキーボード
USB-C ハブ 4,980円 HDMIやUSBポートを搭載したUSB-Cハブ
のように表示されれば、フロントエンドからバックエンド、PostgreSQLまでつながっています。
全体の通信は、
Windows Browser
│
▼
localhost:5173
│
▼
React + TypeScript
│
│ HTTP
▼
localhost:8080
│
▼
Go
│
│ Docker Compose Network
▼
db:5432
│
▼
PostgreSQL
│
▼
products
となります。
PostgreSQLを確認する
必要に応じてCompose設定に合わせてDBへ接続します。次のコマンドはWindows側のPowerShellで、プロジェクトルートから実行します。
cd C:\work\shopping-site
docker compose exec db psql -U appuser -d shop
ユーザー登録の確認なら、例えば次のように必要な項目だけを確認します。
SELECT id, email, created_at
FROM users;
passwordの平文や秘密情報を記事へ掲載しないよう注意します。
問題発生時の切り分け
テストで問題が発生した場合は、層ごとに確認します。
PostgreSQL
↓
Repository
↓
Service
↓
Handler / API
↓
API Client
↓
React Component
↓
Browser
例えば、
Repository Test OK
Service Test OK
API Test OK
Browser NG
であれば、Frontend側のAPI Client、state、画面処理などを優先して確認できます。
商品一覧が表示されない場合は、一度にすべてを確認するのではなく、後ろから順番に切り分けると分かりやすくなります。
まずPostgreSQLを確認します。次のコマンドはWindows側のPowerShellで、プロジェクトルートから実行します。
cd C:\work\shopping-site
docker compose exec db psql -U appuser -d shop -c "SELECT id, name, price_jpy, stock, is_active, description FROM products ORDER BY created_at, id;"
次にGo APIを確認します(http://localhost:8080/api/products)。JSONが返れば、PostgreSQLからGoまでの処理は動作しています。最後にReactを確認します(http://localhost:5173)。
整理すると、
1. PostgreSQLに商品があるか
↓
2. Go APIがJSONを返すか
↓
3. ReactがAPIへ接続できるか
↓
4. Reactが商品を表示できるか
の順番で確認します。ブラウザの開発者ツールでは、NetworkタブとConsoleも確認します。CORSエラー、HTTPステータス、JavaScriptエラーなどを確認できます。
自動テストと手動確認の役割
Unit Test 小さな処理が正しいか
Integration Test 複数層が正しく連携するか
Build コードとして成立するか
API確認 HTTP契約どおりか
Browser確認 利用者として操作できるか
DB確認 永続化結果が正しいか
go test が成功したからブラウザ確認は不要、という関係ではありません。それぞれ確認している範囲が異なります。
テスト前提をFIXして、レビュー工程を収束させる
ここまでの調査では、既存の自動テストについては、一時テーブルやテスト専用Schema、Cleanup/Rollbackなどを利用して独立性を保つ仕組みが確認できました。一方で、全テストケースを実施するには、テスト用DBの接続先確認、大量商品データなど不足するFixture、手動確認用データの準備方法などを補う必要があります。
ここで重要なのは、問題を修正するたびにCodexへ「もう一度レビューしてください」とだけ依頼しないことです。
修正
↓
Codexレビュー
↓
新しい改善点
↓
修正
↓
再レビュー
↓
さらに新しい改善点
という流れにすると、確定仕様とは直接関係しない改善案まで毎回「問題」として追加され、テスト工程が終わらなくなる可能性があります。
そこで、必要な設計判断とテストデータ準備が終わった段階で、テスト前提をFIXします。
docs/の確定設計
↓
docs/test-cases.md
↓
人間レビュー・確定
↓
Codexによる事前調査
↓
不足するFixture/接続設定/仕様差異を解消
↓
────────────────
テスト前提をFIX
────────────────
↓
確定仕様に対する検証へ移行
FIX後のCodexの役割は、新しい改善案を探し続けることではありません。確定済みの docs/ と docs/test-cases.md に実装が適合しているかを検証することへ切り替えます。
Codexが不具合として報告する範囲を決める
FIX後は、Codexが報告する内容を次のように分類します。
| 分類 | 扱い |
|---|---|
docs/ の確定仕様への明確な違反 |
不具合として報告 |
docs/test-cases.md の期待結果を満たさない |
不具合として報告 |
| build/lint/テストが実際に失敗する | 不具合として報告 |
| テスト実行そのものを妨げる環境問題 | ブロッカーとして報告 |
| データ破損・誤更新・重大なSecurity問題が再現した | 不具合として報告 |
| より良い実装方式がある | 今回の不具合にしない |
| 将来的に改善できる | 今回の不具合にしない |
| 一次開発対象外の品質改善 | 今回の不具合にしない |
これはCodexに問題を報告させないためのルールではありません。
例えば、確定仕様でpasswordが8〜72文字なのに73文字で登録できた場合は、明確な仕様違反なので不具合として報告させます。
一方、
プロセスを強制終了すると一時Schemaが残る可能性がある
のような事項が、確定仕様にも test-cases.md にも完了条件として定義されておらず、通常のテスト実行も妨げないのであれば、今回の一次開発を止める新しいブロッカーにはしません。
ポイントは、確定仕様への違反は必ず拾い、仕様外の改善提案で無限に差し戻さないことです。
今回確認できた注意事項の扱いを固定する
今回の事前調査で確認した事項についても、扱いを明確にしておきます。
- 通常の開発用商品seedは、テスト都合だけで100件以上へ増やさない
- PROD-03のように大量データが必要なケースは、テスト専用Fixture/Setupで準備する
- CHECK-05のような特殊な境界データも、通常seedではなくテスト側で準備する
- 自動テスト用データはCleanupまたはRollbackする
- 手動動作確認用データは自動テスト用データと分離する
- ログインが必要なケースでは、ログイン可能な利用者を既存の認証統合テスト方式に合わせて作成する
- Repository / Integration Testでは、第2回で設定した
TEST_DATABASE_URLを使用し、通常のDATABASE_URLと接続用途を分ける - ORDER-08のように設計と既存テストの期待結果に差がある場合は、最新の確定設計と
docs/test-cases.mdを正として扱う - 強制終了時に一時Schemaが残る可能性は、通常のテスト成功を妨げない限り今回のブロッカーとしない
これらを一度決めた後は、同じ事項を「新しく見つかった問題」として何度も差し戻させません。
一次開発のDefinition of Doneを決める
テスト工程を終えるには、開始条件だけでなく**完了条件(Definition of Done)**も必要です。本記事では、一次開発のテスト工程について次を完了条件とします。
一次開発のテスト完了条件
・一次開発として実装した全機能がdocs/test-cases.mdのテストケースまたは明示的な確認対象へ対応している
・確定済みdocs/test-cases.mdの自動化対象を確認している
・自動テストのFAILが0件
・未実行ケースには理由が記録されている
・手動確認対象が識別されている
・go test ./... が成功
・go build ./... が成功
・package.jsonに存在するFrontend検証scriptが成功
・確定仕様に対する未解決ブロッカーが0件
Race Detectorなど、環境や構成によって実行できない項目は、無理に「成功」扱いせず「未実行」と理由を残します。また、ブラウザで確認するよう定義したケースは、自動テストが存在しないことだけを理由にFAILにはしません。
この完了条件を満たしたら、新しい改善候補を探すレビューは行わず、一次開発の自動テスト工程を完了とします。改善案は必要であれば二次開発や別の改善タスクとして扱います。
確定したテストケースからCodexにテスト実装・Fixを依頼する
ここまでで、Workが作成した docs/test-cases.md を人間がレビューし、一次開発のテスト基準として確定しました。
前の工程では、既存テストの調査、不足テストの追加、Unit / Handler / Integration Test、Backend/Frontendの検証を段階的に進めています。ここからは、それまでの結果を引き継ぎ、未完了の作業だけを進めてテスト工程を収束させます。
Codexへ追加の指示を出すたびに、既存テストの調査やPASS済みテストを最初から繰り返す必要はありません。
前回までの成果を確認
↓
完了済み作業を引き継ぐ
↓
未実行・未完了項目を特定
↓
未完了項目だけを実行
↓
FAILがあれば原因を分類
↓
必要な範囲だけFix
↓
関連テストを再実行
↓
Definition of Doneを確認
↓
テスト工程完了
ただし、環境問題などで「未実行」となった項目は完了扱いにしません。 実行可能な環境になっている場合は、前回未実行だったGo Test、Integration Test、build、lint、API・DB・ブラウザ確認などを優先して実行します。
また、一次開発全体のDefinition of Doneを確認するために必要な全体テストについては、個別テストが過去にPASSしていても最終確認として実行します。
今回の目的は、新しい改善案を探し続けることではなく、前回までの成果を引き継ぎ、未完了項目を収束させ、一次開発のテスト工程を完了させることです。
人間 → Codex 指示⑩:前回までの成果を引き継いで最終テスト・Fixを行う
ここまで指示①〜⑨相当の作業を実施済みであれば、ここから人間がCodexへ入力するのは指示⑩だけです。 指示①〜⑨をもう一度実行するのではなく、これまで作成したテストコード、TC-IDとの対応結果、PASS済みの検証結果を引き継ぎます。
ただし、前回までに環境問題で未実行となっているGo Test、PostgreSQL Integration Test、Frontend lint / build、API・DB・ブラウザ確認などは完了扱いにしません。今回はCodex CLIをDev Container内で動作させる構成へ変更しているため、まずCodexにUnit Testを実行させ、すべてPASSしたことを確認してから結合テスト工程へ進みます。その後、CodexにIntegration Testを実行させ、FAILがある場合だけ必要な範囲をFixします。
人間
↓
指示⑩をCodexへ入力
↓
Dev Container内のCodex
├─ 前回までの成果を確認
├─ 未実行・未完了項目を特定
└─ 必要なテストコードを修正
↓
Unit Testを実行
↓
PASS
↓
結合テスト工程へ進む
↓
Integration Testを実行
↓
FAILがあれば必要範囲だけFix
↓
関連テストを再実行
↓
Frontend lint / build・全体検証
↓
必要に応じてブラウザ手動確認
↓
Definition of Done
Codexへ次のように入力します。
docs/test-cases.md を正式なテスト仕様書として使用し、
一次開発で実装済みの全機能についてテストコードを整備してください。
docs/test-cases.md に定義されている一次開発の全機能・全テストケースを対象とします。
ただし、最初からテストコードをすべて新規作成しないでください。
既存実装・既存テストを調査し、
既存テストを最大限利用したうえで、
不足しているテストだけを追加してください。
【重要:前回までの作業結果を引き継ぐ】
この作業は新規に開始するものではありません。
最初に現在のリポジトリ、既存テスト、これまで追加されたテストコード、現在の変更内容を確認し、これまでの作業で実装・検証済みの内容を把握してください。
以降は次の方針で進めてください。
- すでに調査済みで、現在のコードから結果を確認できる作業は再調査しない
- すでに実装済みのテストは再実装しない
- 既存テストとのTC-ID対応付けが確認できる場合は、同じ対応調査を最初からやり直さない
- すでにPASSしており、その後関連コードに変更がない個別テストを確認目的だけで繰り返し実行しない
- すでに追加済みのFixture、Test Helper、Setup / Teardown、テストデータ準備処理を重複して作成しない
- すでに解消済みの仕様差異を再度問題として取り上げない
- すでにCoveredと判断できるTCについて、同じ目的のテストを追加しない
- 未実行・未完了項目を優先する
- FAILが発生した場合のみ、そのFAILに関係する範囲へ戻って原因調査・修正・再テストを行う
ただし、一次開発全体の最終検証として必要な全体テスト、build、lint等については、過去に個別テストがPASSしていても、Definition of Doneの確認に必要であれば実行してください。
過去に「環境問題による未実行」となった項目は完了扱いにしないでください。実行可能な環境になっている場合は、今回の作業で優先して実行してください。
前回までに、docs/test-cases.mdと既存テストの対応調査、既存Fixture / Test Helper / Setup / Teardown / テストデータ準備方式の調査、不足していたBackend / Frontendテストの追加、TC-093の実PostgreSQL経路用テストの追加、TC-008、TC-032、TC-042〜046、TC-049、TC-099〜100に関するFrontend側テストの追加、Frontend Test 50件のPASS確認、設計ブロッカーが存在しないことの確認まで行われています。現在のリポジトリで成果物が存在することを確認したうえで、その結果を引き継いでください。
前回、環境問題により未実行となった主な項目は、gofmt、Go Unit Test、Go Handler Test、Go Integration Test、go build、Frontend lint、Frontend build、API確認、DB状態・制約・Transaction確認、実ブラウザー確認です。今回の作業では、これらの未完了項目を優先してください。
今回はCodex CLIをDev Container内で実行しています。既存のbackend-verify / frontend-verify Skillと現在のプロジェクト構成を基準に、必要な検証コマンドをDev Container内で直接実行してください。テスト実行のためだけに `scripts/unit-test.sh` や `scripts/integration-test.sh` を新規作成する必要はありません。既存の検証スクリプトがある場合は再利用して構いません。`package.json` に存在しないscriptを追加しないでください。まずUnit Testを完全にPASSさせ、その結果を確認してからIntegration Test工程へ進んでください。Unit TestがFAILしている状態でIntegration Testへ進まないでください。
PASS済みまたは完了済みの範囲まで無条件に調査を広げないでください。
今回の基本フローは次のとおりです。
前回までの成果を確認
↓
完了済み作業を引き継ぐ
↓
未実行・未完了項目を特定
↓
未完了項目だけを実行
↓
FAILがあれば原因分類
↓
必要な範囲だけFix
↓
関連テストを再実行
↓
Definition of Doneを確認
↓
手動確認項目を整理
↓
テスト工程終了
今回の目的は、既存作業を最初から繰り返すことではありません。前回までの成果を引き継ぎ、未完了項目を収束させ、一次開発のテスト工程を完了させることを優先してください。
【1. 最初に確認する資料】
以下を確認してください。
- AGENTS.md
- frontend/AGENTS.md
- backend/AGENTS.md
- .agents/skills/
- docs/requirements.md
- docs/use-cases.md
- docs/screen-design.md
- docs/database-design.md
- docs/api-design.md
- docs/open-questions.md
- docs/test-cases.md
確定済みのdocs/とdocs/test-cases.mdを今回の基準としてください。
設計書と実装に差異がある場合、
勝手に仕様を変更して解決しないでください。
【2. 既存テストを調査する】
Backend、Frontend、DB関連の既存テストを確認してください。
特に以下を調査してください。
- *_test.go
- Handlerテスト
- Serviceテスト
- Repositoryテスト
- PostgreSQLを利用するIntegration Test
- React / TypeScript側に既存テストがある場合はそのテスト
- Validatorのテスト
- Fixture
- Test Helper
- Setup / Teardown
- テスト用DB初期化処理
- seed処理
既存テストについて、
- 対応するTC-ID
- テストレベル
- 既に十分確認できているか
- 一部不足しているか
- 未実装か
を整理してください。
既存テストで十分確認できているTCについては、
同じ内容のテストを重複して追加しないでください。
【3. test-cases.mdとの対応を確認する】
docs/test-cases.md の全テストケースについて、
次の状態に分類してください。
- Covered
- Partial
- Missing
- Manual
- NotAutomatable
意味は次のとおりです。
Covered:
既存の自動テストで必要な内容を確認できている。
Partial:
既存テストは存在するが、test-cases.mdの確認内容を一部満たしていない。
Missing:
自動テスト候補だが対応するテストが存在しない。
Manual:
手動確認として定義されている。
NotAutomatable:
現在の構成では自動化対象外。
各TCについて、
対応するテストファイルとテスト関数も確認してください。
この対応確認を行ってから、
不足テストの実装へ進んでください。
【4. 不足している自動テストを実装する】
PartialとMissingのうち、
docs/test-cases.mdで自動テスト対象となっているケースを実装してください。
対象は一部機能ではなく、
一次開発として定義された全機能です。
テスト目的に応じて、
適切なテストレベルを選択してください。
Unit Testでは主に、
- Validation
- email正規化
- password長判定
- 金額計算
- Serviceロジック
- エラー変換
などを確認してください。
Handler Testでは主に、
- HTTP Method
- Request
- Response
- Status Code
- JSON形式
- 認証
- 認可
- Origin
- CSRF
- エラー形式
などを確認してください。
PostgreSQL Integration Testでは主に、
- UNIQUE
- CHECK
- FOREIGN KEY
- Transaction
- Rollback
- Repository
- DBを含む業務処理
- 注文スナップショット
- 在庫更新
- カート更新
などを確認してください。
並行処理を確認するテストケースについては、
PostgreSQLの実トランザクションとロックを利用してください。
単純なMockだけで並行制御が正しいと判断しないでください。
【5. テスト実装ルール】
【テストコードの配置】
テストコードは、既存プロジェクトの配置ルールを最優先してください。
- まず既存の *_test.go の配置を確認してください
- 既存の配置ルールがある場合は、それに合わせてください
- GoのUnit Test / Handler Test / Repository Testは、
原則としてテスト対象コードと同じpackage/ディレクトリの
*_test.go に配置してください
- Integration Testについて既存の配置場所がある場合は、
その構成を利用してください
- Integration Test専用の配置場所が存在しない場合は、
独断で新しいtests/ディレクトリ等を作成せず、
作成前に理由と配置候補を報告してください
- 既存ファイルへ追加できる場合は、
同じ目的のテストファイルを重複して作成しないでください
- テストの都合だけで本番コードのディレクトリ構成を変更しないでください
既存プロジェクトのテスト構造を優先してください。
- 既存Fixtureを再利用する
- 既存Test Helperを再利用する
- 既存Setup / Teardownを再利用する
- テストデータはケース間で独立させる
- テスト順序へ依存させない
- UUID等はテスト間で衝突させない
- DB状態は必要に応じてテスト前後で復元する
- 外部状態へ依存させない
- sleepによる不安定な並行テストは避ける
- Barrier、Channel、Transaction等を利用して競合タイミングを制御する
- 本番DBを使用しない
- 通常の開発用seedをテスト都合だけで変更しない
テストを通すためだけに、
本番コードへ不自然な分岐を追加しないでください。
【6. テストを実行する】
不足テストの追加後、
一次開発全体のテストを実行してください。
Backendはbackend-verify Skillに従って検証してください。
少なくとも、
- gofmt
- go test ./...
- go build ./...
を確認してください。
Race Detectorが現在の環境で実行可能な場合は、
go test -race ./... -count=1
も確認してください。
実行できない場合は失敗扱いにせず、
未実行として理由を報告してください。
Frontendについてはfrontend-verify Skillと
package.jsonを確認し、
実在するscriptだけを実行してください。
例えば、
- npm run lint
- npm run test
- npm run build
などが存在する場合のみ実行してください。
存在しないscriptを検証のためだけに追加しないでください。
【7. FAILしたテストを分類する】
テストがFAILした場合は、
最初に原因を次のいずれかへ分類してください。
- 実装不具合
- テストコード不具合
- Fixture / Test Helperの問題
- テストデータ不具合
- 環境不具合
- 設計書と実装の不一致
- test-cases.mdと確定設計の不一致
- 確定仕様だけでは判定不能
【8. 実装不具合はFixする】
実装不具合であり、確定仕様を変更せず修正できる場合は、
確定済みdocs/を正として実装コードを修正してください。
修正後は、
1. 該当テストを再実行して不具合が解消したことを確認
2. 関連テストを再実行
3. 修正の影響範囲に応じてレグレッションテスト(回帰テスト)を実行
4. Backend / Frontend全体の検証
の順に実行してください。
該当テストがPASSしただけで修正完了としないでください。関連する既存テストを再実行し、修正によって既存機能へ影響が出ていないことを確認してください。
【9. テストコード側の問題もFixする】
テストコード、Fixture、Test Helper、
テストデータに問題がある場合は、
そちらを修正してください。
テストを通すためだけに、
期待値を現在の実装へ安易に合わせないでください。
期待値は確定済みdocs/と
docs/test-cases.mdを基準にしてください。
【10. 仕様差異を発見した場合】
docs、docs/test-cases.md、実装、既存テストの間で差異を発見した場合は、
まず影響範囲を確認してください。
次をすべて満たす軽微な差異は、Workへ差し戻さずCodexで解消してください。
- 一次開発の既存スコープ内
- 新機能・新APIを追加しない
- DB Schemaを変更しない
- 認証・認可方式を変更しない
- セキュリティ要件を変更しない
- 外部インターフェースを大きく変更しない
- 既存の確定仕様から合理的かつ一意に判断できる
- 複数案から人間が選択する必要がない
この場合は必要に応じて、
1. 関連docs
2. docs/test-cases.md
3. 実装
4. テスト
を整合させ、関連テストを再実行してください。
テストを通すためだけに期待値を現在の実装へ合わせるのではなく、
確定仕様を判断根拠にしてください。
【11. 人間の判断が必要な場合だけ停止する】
次のいずれかに該当する場合は、独断で仕様を決めず停止してください。
- 一次開発の機能追加・削除が必要
- 新しいAPIが必要
- DB Schema変更が必要
- 認証・認可方式の変更が必要
- セキュリティ要件の変更が必要
- 外部インターフェースの大きな変更が必要
- 確定済みの主要な業務ルールを変更する必要がある
- 複数の合理的な設計案があり一意に判断できない
- 既存仕様同士が明確に矛盾している
この場合だけ、
- TC-ID
- 関連設計書
- 現在の実装
- 発見した差異
- 判断が必要な理由
- 選択肢がある場合はその選択肢
を報告し、該当テストを「未実行(仕様確認待ち)」として扱ってください。
【12. 手動確認ケース】
Manualまたは自動テスト+手動確認として
定義されているケースについては、
自動テストだけで確認済みとしないでください。
ブラウザ確認などが必要なものは、
- 対象TC-ID
- 操作手順
- 期待結果
を整理してください。
自動テスト部分と手動確認部分を区別してください。
【13. 最終報告】
すべての作業後、次を報告してください。
テスト実装状況:
- 全テストケース数
- Covered
- Partial
- Missing
- Manual
- NotAutomatable
- 今回追加したテスト数
変更ファイル:
変更したファイルごとに、
- ファイル名
- 変更内容
- 対応TC-ID
を報告してください。
Fix内容:
本番コードを修正した場合、
- 発見した問題
- 原因
- 修正内容
- 対応TC-ID
- 関連設計書
を報告してください。
テスト結果:
実際に実行したコマンドと、
- PASS
- FAIL
- SKIP / 未実行
を報告してください。
FAILまたは未実行が残っている場合は、理由を明記してください。
【Definition of Done】
次をすべて確認してください。
- 一次開発の全機能を確認している
- docs/test-cases.mdの全TC-IDを既存テストと照合している
- 自動化対象についてCovered / Partial / Missingを判定している
- MissingまたはPartialの必要な自動テストを実装している
- PostgreSQLが必要なIntegration Testを実DBで確認している
- 並行制御ケースを実DBで確認している
- Backend検証が成功している
- Frontendの利用可能な検証が成功している
- 実装バグを発見した場合は確定設計に従ってFixしている
- Fix後に該当テストを再実行しPASSを確認している
- Fixの影響範囲に応じた関連テスト・レグレッションテストが成功している
- 手動確認対象を別途整理している
- 未解決事項を隠していない
- docs/test-cases.mdの各TC-IDとテストコードの対応を追跡できる
最後に、
「一次開発の全テストケースについて、
どこで・どの方法で確認するのか説明できる状態か」
を確認してください。
改善提案や二次開発向けの拡張案は、
今回の最終報告へ追加しないでください。
今回の目的は、
新しい問題を探索し続けることではなく、
確定済みの一次開発仕様とdocs/test-cases.mdに対して
実装が適合していることを確認し、
必要なFixを行ったうえでテスト工程を完了させることです。
この指示でCodexに任せる範囲
この段階では、Codexに単純なテストコード作成だけを依頼しているわけではありません。
既存テスト調査
↓
TC-IDとの対応確認
↓
不足テスト実装
↓
テスト実行
↓
FAIL原因の分類
↓
実装/テスト/データをFix
↓
再テスト
↓
結果整理
までを一つのテスト実装工程として担当させます。
一方で、仕様そのものを変更する権限はCodexへ渡しません。
確定仕様
↓
Work / 人間
テスト実装・実行・Fix
↓
Codex
という役割分担は維持します。
特に注文確定、在庫、冪等性、並行制御などは、テストを通すために仕様や期待結果を変更してしまうと、テストそのものの意味がなくなります。
そのため、
テスト失敗
↓
原因を分類
│
├─ 実装不具合
│ ↓
│ CodexがFix
│
├─ テスト不具合
│ ↓
│ CodexがFix
│
├─ テストデータ不具合
│ ↓
│ CodexがFix
│
└─ 仕様だけでは判断不能
↓
修正しない
↓
人間へ報告
という境界を明確にしています。
これにより、Codexにはコードを扱う作業を広く任せながら、一次開発の仕様決定そのものは人間側に残すことができます。
今回のテスト工程全体を整理する
ここまでの工程をまとめると、一次開発のテストは次の流れで進めます。前回までに完了している工程は引き継ぎ、未実行・未完了の工程から再開します。
docs/test-cases.md
↓
既存テストとの対応確認
↓
不足テストだけ追加
↓
自動テスト
↓
FAIL → 原因分類 → Fix → 該当テストを再実行
↓
関連テスト・レグレッションテスト
↓
API / Browser / DB確認
↓
Definition of Done
↓
完了判定
Workは設計・テスト設計、Codexは実装・テスト・修正、人間は重要な仕様判断と最終確認を担当します。完了済みの調査やテストを無条件に繰り返さず、環境問題などで未実行だった項目を優先して収束させます。
テスト結果を記録する
結果は成功だけでなく、失敗・未実施も区別します。
| 項目 | 結果 |
|---|---|
| test-cases.mdと実装の対応確認 | 完了 / 未完了 |
| 既存テストとの対応確認 | 完了 / 未完了 |
| Backend Unit Test | 成功 / 失敗 / 未実施 |
| Backend Integration Test | 成功 / 失敗 / 未実施 |
| 自動テスト用データ準備 | 成功 / 失敗 / 未実施 |
| Cleanup / Rollback | 成功 / 失敗 / 未実施 |
go test ./... |
成功 / 失敗 |
go test -race ./... |
成功 / 失敗 / 未実施 |
go build ./... |
成功 / 失敗 |
npm run lint |
成功 / 失敗 / 未実施 |
npm run build |
成功 / 失敗 / 未実施 |
| 既存商品データ確認 | 成功 / 失敗 / 未実施 |
| API確認 | 成功 / 失敗 / 一部未確認 |
| ブラウザ確認 | 成功 / 失敗 / 一部未確認 |
| DB確認 | 成功 / 失敗 / 未実施 |
テストケース仕様書を残すメリット
docs/test-cases.md を残す最大のメリットは、テストコードそのものとは別に、「何を確認する必要があるのか」を設計成果物として管理できることです。しかもこれは第3回でWorkを使って作成し、人間が確定した「設計側の成果物」なので、Codexが書く「実装側のテストコード」と明確に分かれます。例えば実装を変更した場合でも、
requirements.md
↓
api-design.md
↓
test-cases.md(第3回で作成・確定)
↓
*_test.go(Codex)
と影響範囲を追えます。さらに二次開発で機能を追加した場合も、
設計変更
↓
Workがtest-cases.md更新
↓
人間レビュー
↓
Codexが不足テスト確認
↓
テスト追加
という同じ工程を繰り返せます。
テスト成功と実装完了は同じではない
ここはAI開発で特に重要です。
go test 成功
≠
システム全体の完成
例えばBackendテストがすべて成功しても、Frontendが未実装なら利用者は操作できません。反対にブラウザで一度正常操作できても、境界値や異常系、認証・認可の問題が残っている可能性があります。
そのため、
設計
↓
実装
↓
Unit Test
↓
Integration Test
↓
Build
↓
API確認
↓
Browser確認
↓
DB確認
↓
完了判定
という流れで確認します。
テスト工程を終わらせる基準を持つ
AIを使ったレビューでは、指示のたびに新しい改善候補が見つかることがあります。それ自体は有用ですが、すべてを一次開発の完了条件にすると工程が終わりません。
そこで本記事では、
第3回で確定した設計・テストケースを基準化
↓
必要な不足事項を解消
↓
テスト前提をFIX
↓
確定仕様に対して検証
↓
Definition of Doneを確認
↓
一次開発のテスト工程を完了
という区切りを設けました。
これにより、不具合を見逃すためにレビューを止めるのではなく、確定仕様への違反と将来の改善候補を分離して、現在の開発範囲を明確に完了させることができます。
第6回のまとめ
今回は、第3回で作成・確定し、第4回・第5回でも利用してきた docs/test-cases.md を基準として、一次開発の全機能を対象に次のテスト工程を進めました。
-
docs/test-cases.mdと既存テストの対応確認 - 不足しているテストの追加
- テストデータの準備
- Unit / Handler / Integration Testの実行
- Dev Container内のCodexによるテスト実行
- Dev Container内のCodexによるUnit / Handler / Frontend Testの実行
- Unit Testが完全にPASSしてから結合テスト工程へ進む流れ
- Dev Container内のCodexによるPostgreSQL Integration Testの実行
- 人間が各工程のスクリプトを1回ずつ実行し、結果の解析・FixをCodexへ戻す流れ
- APIによる動作確認
- ブラウザによる動作確認
- DBによるデータ確認
- FAIL原因の分類と必要なFix
- 修正後の再テスト
- Definition of Doneによる一次開発の完了判定
また、テスト中に仕様と実装の差異が見つかった場合は、次のように扱いました。
- 確定仕様から一意に判断できる軽微な実装差異はCodexで修正する
-
docs/test-cases.mdのテスト仕様をCodexが独断で変更しない - テスト仕様や重要な設計変更が必要な場合は人間へ戻す
- 必要に応じてWorkで設計を再確認する
- 修正後は関連するテストを再実行する
重要なのは、AIに「全部やらせる」のではなく、工程ごとに役割を分けることです。
- Work → 基本設計・レビュー・テスト設計
- Codex → 実装・テスト・修正・確定仕様内の軽微な差異の解消
- 人間 → 重要な仕様判断・結果確認・最終完了判断
これにより、AIがコードを書けたことではなく、設計した機能が実際に正しく動作していることを基準に開発を進められます。
本連載について
| 回 | タイトル | 対応範囲 | 主な内容 |
|---|---|---|---|
| 第1回 | Docker × VS Code Dev ContainersでGo開発環境を構築する | 🐳 Go開発環境 | Docker Desktop・VS Code・Dev Containersを使ったGo開発環境の構築 |
| 第2回 | React + TypeScript + Go + PostgreSQLのフルスタック開発環境を構築する | 🛠️ フルスタック開発環境 | Docker Desktop・Dev Containers・React・TypeScript・Go・PostgreSQL・Node.js・Vite |
| 第3回 | ChatGPT Workでショッピングサイトを設計してみる | 📐 システム設計 | Project instructions・要件定義・ユースケース・画面設計・ER図・DB設計・REST API設計・テストケース仕様書 |
| 第4回 | Codex × AGENTS.md × Skillsで実装準備を整える | 🤖 AI開発ルール | AGENTS.md・プロジェクトルール・階層化・Skills・実装準備 |
| 第5回 | Codexで設計書からショッピングサイトを実装する | 🛒 ショッピングサイト実装 | 設計書・AGENTS.md・Skillsを活用した段階的なAI開発・実装・検証 |
| 第6回 | Codexで実装したショッピングサイトをテスト・動作確認する | 🧪 テスト・動作確認 | test-cases.md・ユニットテスト・結合テスト・API・ブラウザ・DBによる動作確認 |
| 発展編① | Codexのエージェントハーネスでテスト・デバッグ・再テストを自律化する | 🤖 エージェントハーネス | AGENTS.md・確定仕様・テストケース・停止条件を利用したテスト・デバッグ・修正・再テスト・Regression Testの自律化 |
| 発展編② | Playwrightでブラウザテストを自動化する | 🎭 E2Eテスト自動化 | Playwright・E2Eテスト・ブラウザ操作・Auto-waiting・Trace Viewer・Seleniumとの違い・Codexとの連携 |