リード文
「テストコード書くの面倒くさい…」そう思いながら、カバレッジ40%のまま放置していたプロジェクトがありました。実際にGitHub Copilotを使ってテスト作成を自動化したところ、3時間でカバレッジを85%まで改善することに成功。しかも、自分では思いつかなかったエッジケースまでカバーできました。この記事では、GitHub Copilotを使った実践的なテスト作成テクニックと、カバレッジを劇的に改善するコツを解説します。
背景・課題:テスト作成の3つのペイン
エンジニアなら誰もが経験する「テスト書きたくない問題」。私も例外ではありませんでした。
従来のテスト作成で面倒だった点:
- テストパターンの洗い出しに時間がかかる – 正常系だけでなく、異常系、境界値、エッジケースまで考えると頭が痛い
- モックやテストデータの準備が煩雑 – 外部APIや複雑な依存関係があると、セットアップだけで30分以上かかることも
- 既存コードへのテスト追加が大変 – レガシーコードに後からテストを書くのは、新規開発の3倍疲れる
結果、「とりあえず動けばOK」と自分に言い訳して、テストカバレッジ40%のままリリースしてしまう…。そんな悪循環に陥っていました。
使用したツール・環境
使用ツール:GitHub Copilot(Visual Studio Code拡張機能)
プラン:GitHub Copilot Pro(月額$10)
対象コード:TypeScript / Node.js プロジェクト(Express API)
テストフレームワーク:Jest
GitHub Copilotを選んだ理由:
- エディタに統合されているため、コードを書きながらシームレスに利用できる
- GitHub Copilot Chatを使えば、テストパターンの提案から実装まで一気通貫で対応可能
- 既存コードの文脈を理解して、プロジェクト固有の命名規則やテストスタイルを踏襲してくれる
前提条件:
- VS Codeがインストールされていること
- GitHub Copilot拡張機能が有効化されていること
- プロジェクトに適切な.github/copilot-instructions.mdを設定しておくと精度が上がる
実際に使ったプロンプト
使用したプロンプト
以下のUserServiceクラスに対して、Jest単体テストを作成してください。
要件:
- カバレッジ80%以上を目指す
- 正常系・異常系・境界値テストを網羅
- モックは jest.fn() を使用
- テストデータは describe ブロック内で定義
- エッジケースも考慮する
対象コード:
[UserService.tsのコードをここに貼り付け]
特に以下のメソッドを重点的にテスト:
- createUser() – メール重複チェック、バリデーション
- updateUser() – 存在しないユーザーの処理
- deleteUser() – 関連データのカスケード削除
テストファイル名: UserService.test.ts
プロンプト設計のポイント
GitHub Copilotに任せきりにするのではなく、明確な指示を与えることで精度が劇的に向上します。
工夫した点:
- カバレッジ目標を数値で明示 – 「80%以上」と具体的に書くことで、Copilotが網羅的なテストを生成してくれる
- テストの種類を列挙 – 「正常系・異常系・境界値」と明記することで、思考の抜け漏れを防ぐ
- 技術スタックを指定 – 「jest.fn()を使用」など、使うライブラリやメソッドを具体的に書く
- 重点テスト対象を明記 – すべてのメソッドを均等にテストするのではなく、重要なロジックを優先的に指示
- コードを貼り付ける – プロンプト内に対象コードを含めることで、文脈を正確に伝える
公式ドキュメントにもあるTips:
- 「単一、具体的、短い」コメントを適宜追加する
- import文を先に書いておくと、Copilotが使うライブラリを正しく認識する
- .github/copilot-instructions.mdでプロジェクト固有のルールを定義しておくと、全体的な品質が向上
実行結果・効果:3時間で45%のカバレッジ改善
Before:
- テストカバレッジ: 40%
- テストケース数: 18件
- 作業時間: 手作業で1ファイルあたり約1時間
After(GitHub Copilot使用後):
- テストカバレッジ: 85%
- テストケース数: 57件
- 作業時間: 3時間(5ファイル分)
具体的な改善内容:
- Copilotが自動生成したテストケースの約70%がそのまま使える品質
- 残り30%も、軽微な修正(期待値の調整、モックの微調整)で対応可能
- 自分では気づかなかったエッジケース(空文字、null、undefined、負の値)まで自動でカバーしてくれた
実際の出力例(一部抜粋):
describe('UserService', () => {
describe('createUser', () => {
it('should create a new user successfully', async () => {
// 正常系テスト
});
it('should throw error when email already exists', async () => {
// メール重複エラー
});
it('should throw error when email format is invalid', async () => {
// バリデーションエラー
});
it('should handle empty string email', async () => {
// エッジケース:空文字
});
});
});
想定外だった良い点:
- テストの命名規則(should + 動詞)が統一されていて読みやすい
- describeブロックの構造が論理的で、後から追加しやすい
- コメントも適度に入っていて、何をテストしているか一目瞭然
応用パターン・カスタマイズ例
GitHub Copilotは単体テストだけでなく、さまざまなテストシーンで活用できます。
応用例1: E2Eテスト作成
Playwrightを使って、ログイン画面のE2Eテストを作成してください。
- 正常系: ログイン成功後、ダッシュボードへ遷移
- 異常系: パスワード間違いでエラーメッセージ表示
- エッジケース: 空欄入力時の挙動
応用例2: テストデータのファクトリ生成
Userモデルのテストデータを生成するファクトリ関数を作成してください。
- デフォルト値を設定
- オプションで一部のフィールドを上書き可能に
- ランダムなメールアドレス・名前を生成
応用例3: 既存テストのリファクタリング
以下の重複したテストコードを、describe/itを使って整理してください。
[既存のテストコードを貼り付け]
プロンプトの一部を変えるだけで、さまざまなテストシーンに対応できるのがGitHub Copilotの強みです。
注意点・限界:AIを盲信しないこと
GitHub Copilotは強力なツールですが、すべてを任せきりにするのは危険です。
注意すべきポイント:
- 生成されたテストを必ず目視確認する – 期待値が間違っている場合や、ロジックが不完全な場合がある
- 複雑なビジネスロジックは人間が補完する – ドメイン固有のルールや、微妙な仕様の違いはAIでは完璧にカバーできない
- セキュリティ関連のテストは慎重に – 認証・認可のテストなど、重要な部分は人間がダブルチェックすべき
- カバレッジ100%を目指す必要はない – 重要なロジックを優先的にテストし、getter/setterなど自明な部分は無理にテストしない
AIの限界を理解する:
- Copilotは「提案」であり、「確実な実装」ではない
- 最終的な品質担保は、開発者の責任
- AIをアシスタントとして使い、人間が意思決定する姿勢が大事
まとめ
- GitHub Copilotを使えば、テスト作成の工数を約70%削減できる
- プロンプトに「カバレッジ目標・テスト種別・技術スタック」を明記することで、精度が劇的に向上
- 生成されたテストの約70%はそのまま使えるが、必ず目視確認して品質を担保することが重要
まず試してみてほしいこと:
既存プロジェクトの中で、「テストが薄い部分」を1つ選んで、GitHub Copilot Chatに「このクラスの単体テストを作成して」と頼んでみてください。きっと、思った以上に実用的なテストコードが返ってくるはずです。