Oisix ra daichi Creator's Blog(オイシックス・ラ・大地クリエイターズブログ)

オイシックス・ラ・大地株式会社のエンジニア・デザイナーが執筆している公式ブログです。

Agentic CodingでJavaのレガシーコード100クラス以上にテストコードを書いてもらった

はじめに

技術戦略室の植木です。

最近話題のAgentic Codingで、Javaのレガシーコード100クラス以上にテストコードを自動生成させる試みをしました。

Agentic Codingの話は、モダンな開発での活用が多く紹介されていますが、Javaのレガシーコードへの適用事例はあまり見かけない気がしました。この記事では、その取り組みの背景、実際に行った手法、そして得られた成果について共有します。

なぜやったか

弊社には、長年にわたって開発されてきたJavaのレガシーコードが存在しています。保守・運用や将来的なモダン技術への移行を進めるうえで、コードの信頼性を担保するユニットテストは不可欠です。しかし、現状ではコードの規模に対してユニットテストが明らかに不足しており、この課題を解決するために今回の取り組みを始めました。

しかし、この取り組みに従事できるエンジニアは私一人しかおらず、私も他の開発タスクも抱えている中で100クラス以上に対してテストコードを手動で書くことは現実的でありませんでした。

一方、会社全体でAIを活用した開発効率化に対する機運が高まっていました。 そんな時に、mizchiさんのAgentic Codingに関する発表 にあったプロンプトを見て、これなら人的リソースの制約を克服し短期間でテストカバレッジを向上させることができそうだと考えました。

何をしたか

使用したツール

実際の取り組みでは、次のツールを使用しました。

  • 前半: GitHub CopilotのAgentモード
  • 後半: Claude Code

ツールを変更した理由は、活動の最中にClaude Codeを試す機運が社内で高まったためです。両ツールともAgentic Codingの考え方に基づいており、自律的にコードを理解し、テストコードを生成できました。

目標設定

"AIが認知しやすい明確なゴール" として、JaCoCoのカバレッジ指標を設定しました。

  • Instructions Coverage: 80%以上
  • Branch Coverage: 80%以上

これらの数値を達成することで、最低限の品質を担保したテストコードが書けていると判断することにしました。

カバレッジレポートツールの開発

実は、取り組みを始めようとして早速脇道にそれます。既存のJaCoCoレポートはXML、HTML、CSV形式で出力されますが、これらはAIが読み取って自律的に動作するには適していませんでした。

そこで、脇道へそれついでに JaCoCoのカバレッジレポートを標準出力に表形式で出すGradleプラグイン を作りました。このプラグインには次の特徴があります。

  • 標準出力に表形式でカバレッジを表示(AIも人間も読みやすい)
  • 1クラスを指定してカバレッジを出力可能
  • テスト実行後すぐにフィードバックを得られる

開発したプラグインはOSSとして公開しています:
https://github.com/mas0061/jacoco-coverage-console-plugin

// 使用例
./gradlew test --tests "com.example.MyClassTest" jacocoCoverageConsole -PjacocoClasses="com.example.MyClass"

// 出力例
==================================================================================
JaCoCo Coverage Report
==================================================================================
Class/Package                                      Instruction (%)      Branch (%)
----------------------------------------------------------------------------------
PROJECT TOTAL                                                91.69           91.67
  com.example.MyClass                                        91.69           91.67
----------------------------------------------------------------------------------

このツールにより、AIは各クラスのカバレッジをコンソールで確認しながら、不足している部分のテストを追加していくことが可能になりました。

どうやったか

最初の試み

最初は単純に「このクラスのテストコードを書いて」とAIに依頼しましたが、結果は期待通りにはいきませんでした。AIは一般的なJavaアプリケーションの構造を想定し、次のような問題が発生しました。

  • 存在しないDB接続設定を使おうとする
  • 実際のアプリケーション構成と異なるDIコンテナの使い方をする

AIにはプロジェクト固有のコンテキストが不足していました。加えて、コードベースもそれなりに大きかったため一般論へ頼るのは当然の結果でした。

ペアプログラミングによる学習

そこで、最初の1クラスは次のようにAIとペアプログラミング形式で進めることにしました。

  1. AIが生成したテストコードを一緒にレビュー
  2. プロジェクト固有の設定や慣習を説明
  3. 修正方法を一緒に考えて実装
  4. 動作確認とカバレッジの確認

この過程で得られた知見を、instructionファイル(AIへの指示書)にまとめていきました。

instructionファイルの進化

instructionファイルは、AIがテストコードを書く際の「ガイドライン」として機能しました。最初は簡単な指示から始まり、徐々に次のような内容が追加されていきました。 一見、当たり前に見える記載もありますが、これらはAIが出力するコードの特性に応じて指摘し追加してもらったものです。

## Javaユニットテスト

### 基本方針
- JUnitのテストケースでDBにアクセスする部分はモックを使わない
    - テストでDBにアクセスする場合、利用するDBMSは共通部分で決定するのでテストケースでは意識しない
    - テストに必要なテーブルは作成済みの前提でテストケースを書く
- JUnitのテストケースを自動で作成する際は、productionコードを変更せずに成功するテストケースを作成する
- **テスト例外処理方針**: try-catchで例外を隠さず、例外が発生すれば自然にテスト失敗とする。Oracle特化のSQL構文で実際に失敗が確認された場合のみ、TODOコメントで原因と対応方針を明記する
- **冗長テストパターンの排除**: `assertTrue("メッセージ", true);` のような意味のないアサーションは削除し、適切なコメントに変換する

## テストカバレッジ目標とアプローチ
カバレッジを目的としたテストコードの作成をする場合、目標カバレッジまで段階的にテストコードを書いていく。

1. 対象クラスのテストクラスが存在するか確認する
    1.1. 対象クラスのテストクラスが存在する場合、テストを実行して現在のカバレッジを確認する
    1.2. 対象クラスのテストクラスが存在しない場合、テストクラスを作成する
2. テストコードを実装する
3. テストクラスを実行し、カバレッジを出力する
4. 現在の状態から最もカバレッジが上がるテストコードを考察してから追加する
5. 再度カバレッジを計測して、数値が向上していることを確認する

これらをユーザーが満足するまでテスト生成を繰り返す。
なお、カバレッジを上げるのが困難な状況も予想されるため、カバレッジが10%上がるごとにユーザーへ継続意思を確認してほしい。
ユーザーが満足したら、カバレッジを維持したままリファクタリングをする。

テストコードが書けたら、 `./gradlew spotlessCheck` でフォーマット違反がないことを確認し、違反がある場合は `./gradlew spotlessApply` で修正する。

- **目標カバレッジ**: Instruction Coverage、Branch Coverageともに80%以上
- **段階的改善**: 初回60% → 追加実装で80%+ を目指す

Excelファイル問題への対応

既存のテストコードでは、DBのテストデータをExcelファイルで管理して流し込む形になっていました。しかし、バイナリファイルはAIとの相性が悪く、次の問題がありました。

  • AIがExcelファイルの内容を直接読めない
  • ファイルの更新が面倒
  • バージョン管理での差分確認が困難

途中、ExcelファイルをAIが読めるようにMCPを使う試みもしましたが、ファイルが大きくなると処理が重くなったり、コンテキスト理解が難しそうだったので断念しました。

最終的に、テストデータは直接Javaへ直接記述する方針に変更しました。元々、その方が良いと思っていたので、これを機に変更できて良かったです。

どうだったか

成果

約1ヶ月の取り組みで、次の成果を達成しました。

  • 100クラス以上のテストコードを1ヶ月ほどで作成完了
  • 平均カバレッジ: Instructions約85%、Branch約60%

instructionファイルの威力

instructionファイルを充実させた結果、後半では「HogeClassのテストコードを書いて」と依頼するだけで、次のようなプロジェクトの慣習通りの適切なテストコードが生成されるようになりました。

  • 適切なDBの使い方
  • プロジェクト固有のユーティリティクラスの活用
  • 一貫性のあるテストデータの作成方法
  • カバレッジ目標を意識したテストケースの網羅

得られた知見

この取り組みを通じて、次の重要な知見を得ました。

  1. 初期の学習投資が重要: 最初のクラスでしっかりとAIに学習させることで、後の効率が大幅に向上
  2. 明確な目標設定: カバレッジという数値目標があることで、AIも人間も進捗を把握しやすい
  3. 適切なツールの準備: AIが読みやすい形式でフィードバックを得られる環境が必須
  4. 継続的な改善: instructionファイルを継続的に更新することで、品質が向上

今後の展望

今回の取り組みで、Agentic Codingの可能性を実感できました。今後は次のような発展を考えています。

  • より複雑なビジネスロジックを持つアプリケーションへの適用
  • 単体テストだけでなく、統合テストやE2Eテストへの拡張
  • instructionファイルのテンプレート化と他プロジェクトへの展開
  • カバレッジだけでなく、テストの質(アサーションの適切さなど)の向上

まとめ

Agentic Codingを活用することで、人的リソースの制約を克服し、短期間で大量のテストコードを生成できました。重要なのは、AIに適切なコンテキストと明確な目標を与え、継続的にフィードバックループを回すことです。

この取り組みが、同じようにレガシーコードのテスト不足に悩んでいる方々の参考になれば幸いです。

Oisix ra daichi Creator's Blogはオイシックス・ラ・大地株式会社のエンジニア・デザイナーが執筆している公式ブログです。

オイシックス・ラ・大地株式会社では一緒に働く仲間を募集しています