Upgrade to Pro — share decks privately, control downloads, hide ads and more …

20年もののレガシーJavaプロダクトに自動テストを組み込んできた話(再)

 20年もののレガシーJavaプロダクトに自動テストを組み込んできた話(再)

2026年3月度関ジャバでの発表資料です。
https://kanjava.connpass.com/event/387904/

X
https://x.com/gengenmusic0719
lit.link
https://lit.link/gengen0719

Avatar for げんげん

げんげん

March 31, 2026
Tweet

More Decks by げんげん

Other Decks in Technology

Transcript

  1. 保守してきたプロダクトの紹介 とあるERPパッケージソフト → SaaS 保守期間20年越え Javaソースコード 約380万⾏ 開発組織の⼈員は 約50名(当時) Java

    1.4時代のコードが残っている 当初からWebアプリとして作られているので、JSPの実装が残っていたり、 ⾊んなフレームワークの実装が地層のように積み重なっている。 このプロダクトに⾃動テストの仕組みを整備してきた経験と、新しいプロダ クトを作る際に⾃動テストを整備している経験をもとに話します。
  2. JUnit TestをCIで⽇次実⾏する Small sizeのTestをCI上で実⾏することは全く難しくありません。 JavaでGradleを利⽤している場合であれば標準の test タスクを実⾏すれば良いです。 GitHub Actionsで毎⽇夜 9:30に

    テストを実⾏するのであればこんな感じです。 ⾮公開の内製ライブラリに依存する場合は 認証や通信経路確保などが必要になりますが、 それもそこまで難しい話ではありません。 しかしテストは書いているけど CIで実⾏する仕組みはないというプロダクトは 意外と多い
  3. JUnit TestをPre mergeで実⾏する より早く検証の失敗を検知できるように Small SizeのテストはPre mergeにも組み込んだ⽅が良いと思います Pre mergeとはマージされる前、という意味で、 Pull

    RequestやMerge Requestが作成された際にテストを実⾏し、 失敗した場合はmainブランチにマージされるのを防ぐことができます。 これによって他の開発者に影響する前に検証を⾏うことができます。 また修正者が間違いなく⾃分の修正によって失敗したことを把握できる という点も利点です。
  4. 啓蒙活動 - テスト駆動開発の動画視聴会 TDD Boot Camp 2020 Online #1 基調講演/ライブコーディング

    https://www.youtube.com/watch?v=Q-FJ3XmFlT8 - JUnit の基礎知識の勉強会 - レガシーコードにUnit Testを書くためのテクニックの勉強会 レガシーコード改善ガイドの内容を実際のプロダクトコードに適⽤ - 外部講師の⽅を招いた全社向けの講演 開発組織全体の盛り上がりの醸成と経営層への単体テストの重要性の訴求
  5. やったこと 実現するために以下が必要だった - データベースにアクセスするテストとしないテストの実⾏を分離 - テストクラス内でDataSource、Connectionを取得する仕組みを整備 - 開発者やCIで利⽤するデータベースのDocker Imageを整備 -

    テスト時のデータベースのデータの扱いのルールを整備 データベースを扱うことで⾊々な準備が必要になり、仕組みも⼤がかりに。 CIでのテスト実⾏時には全てのテストが同じデータベースを使うため、データ管理 の戦略も必要。 プロダクトの固有の事情によって異なる部分が多いものだと思いますが、 できるだけ根拠を含みつつ話しますので、⼀事例として聞いていただければと思い ます。
  6. 仕組みの実装 - データベースに接続するテストコードはmain, test とは別のフォルダに置くようにする - 専⽤のアノテーション @DatabaseAccessTest を作成 データベースにアクセスしたいテストにはこれをつけるようにする。

    - gradle に databaseAccessTest というタスクを作成する - CIや開発者の端末で動かせるデータベースのDocker imageを準備(後述) - テスト⽤のConfigurationでlocalhostのデータベースへの接続を取得する仕組みを整備 (Spring未対応のコードが多いのでConnectionやDataSourceを取得するUtilityも⽤意)
  7. 仕組みの実装 これで開発者の端末のIDEでは - @Test がついたテストはいつでも実⾏できる - @DatabaseAccessTest がついたテストはテスト⽤のデータベースを起動したら実⾏できる CI上では -

    gradle test で @Test がついたテストが実⾏できる - gradle databaseAccessTest で @DatabaseAccessTest がついたテストが実⾏できる (CI上にデータベースを起動する必要がある) という状態になりました。 開発者ローカルで実⾏する際の使⽤感を変えず、かつ データベースに接続するかどうかで明確にCIでの実⾏を分離できるように、 このような実装にしました。
  8. ⾃動E2E Testの必要性 これまで Small, Medium のテストを整備してきたが これらだけでは最終的な結合テストとしては不⼗分なため 品質保証としてのテストをカバーしきることができない - モジュール間の結合箇所の担保の説明が難しい

    - クラウドサービス等の動作に依る部分が検証できない 打鍵⼯数の削減やアジリティの向上に繋げるには、 E2Eの⾃動テストが必要であると考えています (範囲は狭く保ちつつ)