GitHub Copilotを使ってPoCとして開発していたアプリケーションが、ある程度動くところまで来ました。その過程で、失敗を通してCopilotを前提にした開発フローをいろいろ試行錯誤したので、E2E(End-to-End)テストを含めた開発フローのPoC事例としてまとめます。この記事を作成した時点でE2Eテストはおよそ30シナリオ400ステップ、起票したIssueはおよそ400件です。今回のPoCで得られた結論は次の3点です。
- Coding AgentにE2E実行から分析までを任せるのは不安定
- E2Eは「最終確認」ではなくCopilotの評価基盤になる
- 責任境界はツールではなく運用とプロンプトで補強する必要がある
Copilotは非常に強力で、PoCの立ち上げスピードを大きく引き上げてくれました。一方で、生成されるコードや修正内容は指示の与え方に強く依存します。そこで今回のPoCでは、E2Eテストを開発フローに組み込み、E2Eテストを通してCopilotの出力を確認しながら回す形を試しました。
この記事は、E2Eテスト込みの開発が安定運用できている、というものではありません。あくまで、Copilotにどこまで任せられそうか、E2Eテストと組み合わせるとどこで詰まりやすいのか、といった点について、PoCで得られた知見を整理したものです。
本文中では、以下のように表記を簡略化しています。
- Copilot:GitHub Copilot の総称
- Coding Agent:GitHub Copilotのコーディングエージェント
- Agentモード:VS Code上で利用する Copilot Agent モード
PoCの前提と検証対象
今回のPoCはモノレポ(Mono Repository)で、GUI / BFF / 複数マイクロサービス / E2Eテストがディレクトリで分離されて単一リポジトリに同居する構成としています。
また、体制としてはE2Eテスト担当と各実装担当がそれぞれ別チームになっている想定とし、「他チームの担当領域は直接修正せず、そのチームを担当とするIssueを作成する」というルールを置いています。
その上で、本PoCでは以下を検証対象としました。
- CopilotにE2E実行・分析を任せられるか
- モノレポ+チーム分離構成で責任境界は維持できるか
- E2Eを評価基盤にすることで修正ループは安定するか
Pocの開発フロー(1):テスト→修正のループに入るまで
最初に簡単な要求定義書を作成し、AIと壁打ちしながら内容を膨らませました。PoCなので規模は抑えつつ、複数ドメインを横断するアプリケーション開発を試行できる要件となるよう意識しました。
その後、ドメイン分割を行い、GUI・各マイクロサービスの仕様とコードをCoding Agentで生成しました。E2Eシナリオ(Gherkin)とテストコード(Cucumber + Playwright)も同様に生成しています。
ここまでは比較的スムーズに進みました。
Pocの開発フロー(2):テスト→修正のループ
今回のPoCでいちばん時間がかかった部分で、この記事のメインの話題となるのは、テスト→修正のループです。
PoCの最初期は、E2E実行も分析も修正も、できる限りCoding Agentに寄せたら最短で回るのではないかと考え、下の図のような分担にしていました。図で、青がCoding Agent、オレンジが人手です。
「E2Eテスト実行」、「各失敗について原因分析」、「原因ごとにIssue作成」をまとめてCoding Agentの1セッションで実行していました。このときに失敗の原因がE2Eテスト側にあるようなケースもあります。
Coding AgentではGitHub Issueの起票はできないようになっている(とCoding Agentが言っている)ので、Issueの内容はファイルに書いてGitにコミットさせます。Issueには失敗の原因によって、担当するチームも書かせます。
Issueが作成されたら、「各Issueの発行」、「各Issueのアサイン」を人手でGitHub上で行います。
IssueをアサインされたCoding Agentが「各Issueの解決」を行います。マイクロサービス単位で分離されているので、コンフリクトすることなく複数のマイクロサービスの修正をそれぞれ並行して進めることができます(少なくともルール上は)。
直面した問題
このフローで何回かテスト実行→修正のループを回していると、以下のような問題に遭遇しました。
エビデンスが残らない
E2Eテスト担当(E2Eテスト担当役のCopilot、以下同様)と実装担当の間でたらい回しが発生しました。実装側が修正しようとした結果、問題が見つからずに「これはE2Eテストコードの問題です。」と回答してきます。そこでE2E側にIssueをアサインすると、E2E側は「これは実装側の問題です。」と返してIssueが解決しないという状況です。
Coding AgentはGitHub Actions上で動作するので、セッション終了後に実行結果が消えてしまいます。たらい回しの原因を調査するために、ログやスクリーンショットをコミットするよう指示しても、ログの抜粋だけがコミットされ、生のエビデンスがコミットされずに調査が進まないということが起きました。
責任境界を超えて修正する
「他チームの担当領域は直接修正しない」というルールは明示しているのですが、実際にCopilotにIssueをアサインすると、指示した担当領域を越えて変更が混ざってしまうことがありました。例:
- E2Eテスト担当に「失敗原因の分析」を依頼したにもかかわらず、実装側のコードまで修正した
- GUIの修正を依頼したところ、関連するBFFやバックエンドのコードまでまとめて修正した
改善後:ローカル実行+Agentモードでの分析へ
そこで、人とCopilotの役割分担を見直しました。下の図で、青がCoding Agent、オレンジが人手、紫がVS Code上のAgentモードです。
変更点は、E2Eテスト実行からIssue作成までをローカルのVS Codeで行うようにしたところです。これにより、前述のエビデンスが残らない問題が解消しました。
「E2Eテスト実行」の部分は人手で実施する運用に落ち着いています。Coding Agentでは(GitHub Actions上で動作しているので)別のセッションへの実行結果の受け渡しが困難(コミットしてくれない)なため、実行と分析を切り離すことはできませんでした。ローカルでE2Eテストを実行するようにしたことで、実行結果を全て残せるようになり、E2Eテスト実行をCopilotに任せる必要がなくなりました(任せてもいいけど、Copilotは実行が完了するのを待つだけ)。
原因分析とIssueの作成でのAgentモードへの指示の概略は、以下のようになっています。
-
失敗したシナリオの抽出
Cucumberのログから、失敗したシナリオを抽出します。 -
失敗原因の調査
各シナリオについて失敗の原因を調査します。 -
Issueファイルの作成
同一原因と思われる失敗は1つにまとめて、Issueファイルを作成します。 -
サマリレポートの作成
人が各Issueの状況を把握しやすいようにサマリを作成します。サマリレポートには、失敗したシナリオとそれに対応するIssueというシナリオ観点の報告と、今回のテストで発生したIssue・解決したIssue・解決しなかった(前回から継続している)Issueという形でのIssueの棚卸を含めています。
3.について、AgentモードはCoding Agentとは異なり、GitHub Issueの起票ができます。そのため、ファイルを作成させて人手でGitHub Issueを起票するのは二度手間とも考えられるのですが、Issueの解決を実行するCoding Agentと運用が変わってしまうため、共通化のためにファイルとしてIssueを作成しています。
4.について、Issueが解決済みか否かは、今回のE2Eテストの結果で判断することをルールとして明記しました。実装側がIssueの履歴として「解決」と書いたことを根拠に解決済みであると判断することがあったためです。
Issueの棚卸をして、解決しなかったIssueではたらい回しが発生している可能性がありますので、Issueの内容とアサイン先について人手で精査します。このとき、必要に応じてE2Eテストのエビデンスを調査することもあります。
考察
今回のPoCでは、E2Eテストチームと実装チームを分離し、「他チームの所有物は直接修正しない」という制約をあえて置きました。単一チームの構成であれば、ここまで厳密なIssue分割や、役割・責任を意識した運用は正直不要だったと思います。それでも今回この前提を置いたのは、実運用に近い形でCopilotを使ったときにどうなるかを、PoCの段階で確認しておきたかったからです。
ドキュメント・実装・E2Eテストが一緒に育った
今回のPoCでは、ざっくりした要件から実装、テストを進めて一緒に育てました。最初から要件が明確になっているわけではないため、「正しいE2Eテスト」を用意してそれに実装を合わせるという進め方はできませんでした。
- 実装が変われば、テストの前提も変わる
- テストを書いてみて初めて、仕様の曖昧さに気づく
- 仕様を明確にすると、実装側の修正点が見える
このループの中で実装の理解が深まり、E2Eテストの粒度や厳しさも適切になっていきました。
PoC初期のE2Eテストは、フォールバックが多かったり、仕様を“ぼんやり”確認しているだけという状態でしたが、Issueを起点に失敗原因を整理することで、「ここは厳密に見るべき」「ここはE2Eで見る必要がない」といった判断が少しずつできるようになりました。
E2Eテストは「最終確認」というだけでなく、Copilotの出力を確認しながら進めるための基準点としての役割を持っています。つまり、Copilotが出力した不確実性を含んだ出力に対し、仕様という制約を満たすかどうかを判定する評価基盤です。E2Eを回すことは、その評価基盤を整備することだったと考えています。
BFFを誰のものとすべきか?
GUI → BFF → バックエンドという構成では、BFFをどのチームの責任範囲とするかでCopilotの振る舞いも大きく変わると感じました。
今回のPoCではBFFを別チームとしていましたが、Copilotから見ると、BFFはGUIの延長にもバックエンドの一部にも見えるため、修正範囲が曖昧になりやすい構造でした。結果として、GUIの修正を依頼したはずがBFFやバックエンドまで変更される、ということが起きました。少なくともCopilotを活用する前提では、BFFは「どのチームの責任範囲か」を人間同士で明確に合意し、依頼文にも明示しておく必要があると感じています。
PoC段階ではBFFをGUIチームの責任範囲として扱った方が境界が単純になり、安定しやすいかもしれません。
モノレポで責任範囲を分ける話:CODEOWNERSは効くのか?
今回のPoCはモノレポで進めています。だからこそ「他チームの担当領域は直接修正しない」というルールを置いているのですが、実際にCopilotを動かしてみると、指示した担当領域を越えて変更が混ざってしまうことがありました。
ここで候補に上がるのがGitHubのCODEOWNERSです。CODEOWNERSは、特定のディレクトリやファイルの“オーナー(責任者)”を定義できる仕組みで、ブランチ保護の設定と組み合わせると「コードオーナーの承認がないPRはマージできない」を強制できます。
結論から言うと、CODEOWNERSで解消できるのは「担当外の変更がmainに入ってしまう」問題です。Copilotが担当外まで修正したPRを作ってしまうこと自体は起こり得ますが、コードオーナー承認必須にしておけば、そのPRは担当チームの目を通らない限りマージできません。
一方で、CODEOWNERSだけでは「担当外の変更がPRに混ざること」をゼロにはできません。Copilotは“全体の整合性”を優先して修正を進めることがあり、指示した範囲外のファイルにも手を伸ばすことがあります。このとき、CODEOWNERSは“混ざった変更を止める最後の砦”にはなりますが、“混ざらないようにするガードレール”としては弱い、という感触です。
CODEOWNERS(マージの強制)に加えて、運用として「担当領域を越えた変更が入ったらPRを分ける/差し戻す」を明文化し、Copilotへの指示にも「変更してよい範囲(パス)」を必ず書くのがよさそうです。
まとめ
今回のPoCでは、E2Eテストという評価基盤を導入することでCopilotの不確実性を抑えられる手ごたえがありました。最初にやっていた「Coding Agentにまとめて任せる」形は、思ったより不安定でした。特に厳しかったのは、エビデンスが残らず原因が追えないことと、モノレポ構成ゆえに修正が担当領域を越えて混ざりやすいことです。
E2Eテスト実行をローカル環境に寄せることで、エビデンスを残して人手で確認できるようになり、その結果、たらい回しを解消できるようになりました。
責任境界問題の決定的な打開策は見えていません。今後もチームの責務の見直しやプロンプトの改善に取り組んでいきたいと考えています。
本文中に記載の会社名、製品名などは、それぞれの会社の商標もしくは登録商標です。
商標記号(™、®)は明記していません。