LegalOn Technologies Engineering Blog

LegalOn Technologies 開発チームによるブログです。

JaSST24’Tokyoで「生成AIでテストコード生成の効率化」をテーマに登壇しました

2024年3月の14〜15日に開催されたJaSST’24 Tokyoというソフトウェアテストシンポジウムに「生成AIを使ったテスト記述の最適化と生産性向上」をテーマに登壇しました。

こんにちは!LegalOn TechnologiesでSoftware Engineer in Test(SET)をしている山本です。

本記事では、登壇の発表内容や感想についてお話できればと思います。

※オンライン登壇であったため、写真を用意することができず申し訳ありません。

セッション概要

登壇に至った背景

実はこの登壇を決めたのは、2024年1月に入社する前でした。

当時はChatGPT3.5が出た頃であり生成AIに衝撃を受け、それ以来どのように開発に取り入れることができるかを模索し続けていました。

更に生成AIを使用したコードエディタの入力補完に特化したツールであるTabnineやGitHub Copilotも登場し、導入するだけでもコーディング時間が1割ほど短縮されました。単調な部分のコーディングから少しずつ開放されはじめ、当時リソース不足に悩まされて手を付けられずにいたテスト自動化の推進に希望が見え始めてきました。

テストコードへの応用にも取り組み、各テストの前後に実行されるフィクスチャや似たようなテストケースの生成で役立ちました。

一方で、メンバー間のコードの書き方の違いによるAIへの影響や、開発が進むにつれてプロンプトを利用した生成内容の再現性が低下し、開発者の意図と異なるテストコードが生成されていました。

詳細は後述しますが、生成AIに1行ではなく複数行のテストケースの生成を行わせることによりこれらの問題が解消され、2割くらいのコーディング時間短縮となりました。

SETの島根と入社前に話す機会があり、お話していくとJaSSTに登壇するといいのではないか?と提案をされ、AIにどうテストコードを書かせるか?という話は少ないと感じ応募を決めました。

発表したこと

GitHub Copilotなどの生成AIをどのように使用すればより効率的にテストコードを書くことができるのか?について話しました。

下記が発表に使用したスライドです。

https://speakerdeck.com/patt812/jasst24-tokyo-c7-1-optimizing-test-using-generative-ai

特に伝えたい部分を下記に書いていきます。

基本戦略として「大きな補完」を目指す

本スライドのメインとなるテーマです。

ここでいう補完とは、「コード入力後に生成AIが作成したコードの提案を受諾する」ことを指します。

補完の大きさは、提案する行の多さを意味します。

AIによるコード補完はまず長めの行数を提案しますが、開発者からの提案拒否が続くと徐々に提案する行数が短くなっていく傾向があります。

施策を行う前では1行レベルの補完しかありませんでした。

そのため、以下の課題がありました。

  • 補完が多いので判断回数が増え開発者の負担になる
  • 長いプロンプトを打ち込んでも1行しか生成されないため、費用対効果が合わない
  • 同じプロンプトでも出力結果が異なることが多い

一方で、大きな補完ができれば1回の補完で1テストケースごとの生成ができます。

そのため、大枠の生成をAIに任せ細部の修正に集中することができます。

試行錯誤をしてたどり着いた大きな補完

大きな補完はすぐにたどり着けたものではなく、様々な試行錯誤がありました。

  • コメントに詳細なプロンプトを書いて複数行の生成を狙う
  • AIに参照してほしいタブのみを開き、見てほしい情報を強調する
  • API定義などを一時ファイルとして置き、編集中のファイルにない情報をAIに参照させる

これらの施策を行いましたが、欲しいコードと異なる提案が多く、うまくいっても後で再現されなくなるケースもありました。

また、提案は1行の生成がほとんどであり、施策の割に大きなリターンを得られている感覚はありませんでした。

しかし、課題となっていた自動テストの導入でシンプルなテストを書いていたとき、テストコードに繰り返しの部分も多く、提案を受諾する数が増えました。

受諾を繰り返すと1行ではなく1つのテストケースの単位で生成してくれるようになりました。

これにより、別のファイルで書かれていた既存のテストケースをベースに生成されるので、特別なプロンプトや準備が不要になりました。

この仮説を施策に落とし込めばテストを書くリソースの確保ができると考え、具体的な取り組みを始めました。

施策として開発に組み込む

施策は概ね順調ではありましたが、個人からチームという単位になると、開発者によってテストを書く順番やシンタックスシュガーを使うかどうかの違いが大きく、その結果生成されたコードが受け入れられず、短い補完が当たり前となっていました。

そこで大きな補完を実現するため、主に以下の施策を最終的に実施しました:

  1. 大まかなテストの書き方を決める

    まず、テストコードの書き方をデータの準備→テストの実行→アサーションという順番で書くようにしました。この順番はどのテストでも守られている印象があるかもしれませんが、テストの実行時に引数へハードコーディングされたデータが渡ることもあり、準備と実行が同時にされているテストもありました。そうではなく、変数やファイル読み込みを利用して準備、実行、アサーションの手順を独立させるようにしました。

  2. 目指す補完の粒度を定義し、複数行の提案は基本受諾するようにする

    補完を1テストケース単位の粒度で行う方針に変更し、大枠を生成してから細部を修正するようにしました。大枠の提案の受諾が少ないと1行ごとの生成に戻ってしまうため、大枠の流れに問題がなければ、多少意図しない部分があっても大きな補完を受諾することとしました。

  3. 実装するテストの順番を統一

    テストフィクスチャ、ハッピーパスのテスト、エラー系のテストを書く順番を統一することで、開発者が書くテストの種類と提案されるテストの種類が一致しやすくなり、提案拒否が減少しました。

  4. 開発者によって書き方に違いが出そうな部分を統一

    加えて、ラムダ式などのシンタックスシュガーをつかうかどうかや、どのアサーションライブラリを使うかも統一し、どの開発者が書いても違いが出にくいようにしました。これも提案拒否を減らすことに繋がりました。

大きな補完を実現するためには、特に1と2の施策が重要であると感じました。

テストの書き方、つまり構成を決めることにより、生成AIがどのようにテストを書けばいいのかを理解してくれたように見受けられました。

そして、それらの提案を受け入れる事により、開発者がそのようなコードを求めているかがAIにも伝わり、「準備→実行→確認という構成で、一つのテストごと生成したほうがいい」という認識がAIに根付いたようにも思えます。

これらの施策の結果、GitHub Copilotによる大きな補完ができるようになり、テストケースを多く作成できるようになりました。 開発者は、大きな補完に対して数行の修正を行えばよくなり、テスト自動化の推進に役立ちました。

また、単純なコピーペーストによる追加方法と異なり、変数名やアサーションエラー時のログを書き換えた状態で生成してくれる利点があります。

施策を推進する上での注意点

この施策を振り返って、注意点や改善できたと思うポイントについて書きます。

生成されたコードは良くも悪くもパターン化される

大きな補完は、生成を続けると既存のテストコードの書き方をベースに細かい部分を修正した生成を繰り返す傾向がありますので、既存のコードの領域をはみ出た提案をすることがなくなります。

そのため、新たな視点を取り入れるための人材採用は必要不可欠ですし、生成されたコードから気づきを得るチャンスは失われます。

大きな補完は、一緒にAIとコードを書いていくというよりは、以前書かれたコードの範囲で書かせるということになり、割り切った生成AIの使い方となります。

プロダクトコードをベースとしたテストになるリスクがある

質疑応答でもありましたが、注意点として、生成AIのみでテストを完結させることはプロダクトコードをベースとしたテストであり、正当性の検証が不十分になるリスクがあります。

そのため、生成されたテストコードの検証についても必要となります。

今後の課題

スライドの最後では、今後の課題としてプロンプトを資産にできなかった点を挙げました。

今回チャレンジした施策である「生成AIを活用した開発」は個人のプロンプト応用にとどまっており、チーム内で工夫が共有されていなかったという課題が残っています。

個人的に生成AIの活用法は個人で完結することが多く、組織レベルで話し合われることは少ない印象があります。

例えば、ドキュメントベースなどで実務を踏まえたプロンプトの例が共有されていれば、プロンプトの使用法をチーム間で統一でき、プロンプト改善の議論を行う場所を提供することができると感じました。

GitHubはIssueひとつの作成でAIが設計からコーディング、テストをサポートできるGitHub Copilot Workspaceのリリースを予定しており、自然言語でコーディングできる範囲が広がるためよりプロンプトが重要になると考えています。

まとめ

生成AIにテストを任せるという観点ではなく、生成AIに書きたいコードを出力させるという認識が重要です。

そのためには、まずテストコードの流れを決め、AIにどういうテストコードを書いてほしいか?という部分を取り決める必要があります。

シンタックスシュガーなど、開発者により書き方に差が出る部分をチームで決めることも役立ちます。

次に1回の提案で1行の出力ではなく、1テストケースの出力を目指します。

提案の拒否が続くと1行のみの出力に戻るため、多少意図しない出力があっても受諾をしてから修正をする方針としていました。

これにより、大枠のテストケースをAIが作成し、細部の修正を基本とすれば良くなります。

以上、統一されたテストの書き方と大きな補完の受け入れ基準を決めることで、テストコードの生成を行単位からテストケース単位に引き上げ、開発リソースが少ない中でもテストの自動化を推進する結果を得ることができました。

振り返ると、統一されたテストの書き方と大きな補完の受け入れが重要だったと感じています。

参考資料:登壇した際の質疑応答

https://speakerdeck.com/patt812/jasst24-tokyo-c7-1-optimizing-test-using-generative-ai?slide=38

JaSST’24 Tokyoに参加した感想

発表中セッションの接続数が常時270名近くとなり、非常に緊張しました。

司会者が進行を担って頂いたこともあり、なんとか発表に集中することができました。

また、登壇が決まった段階から実行委員の方から早めに連絡を下さり、非常にスムーズに準備ができました。

実行委員会の方にこの場を借りて厚く御礼を申し上げます。

他のセッションも聴きましたが非常に魅力的で、品質とはなにか?を深く考えさせられるセッションが多く、参加して本当によかったと思っています。

特に、基調講演のGojko AdzicさんのTangible software qualityという講義が興味深かったです。

https://jasst.jp/symposium/jasst24tokyo/report.html#keynote

バグかない製品で品質をどう評価するか?という問いが興味深く、品質もqualityではなくqualitiesと複数形を満たせるように追求するという気付きが良かったです。

多くのセッションで手段が目的にならないように気をつけなければいけないことが強調されている印象で、安直なメトリクスの導入に満足してはいけないということが大きな学びでした。

登壇を終えて

登壇を終えて今後、より更に生成AIを使ったテストコード生成の最適化を実現したいと思えました。

GitHub公式がβ版としてCopilotのメトリクスを取得できるAPIを公開したため、メトリクスに基づいた改善も実現したいです。

また、複数の言語やエディタをまたぐ最適化はまだ経験がないので、開発環境に依存しない生産性の向上を狙っていきたいです。

メンバーを募集しています!

株式会社LegalOn Technologies では、QAやエンジニアの垣根、領域を超えて高いスピードで高品質を実現するために日々開発を進めています。

一緒に働きたいと思えたら、ぜひ気軽にご応募ください。

お話だけでも大歓迎です!

https://herp.careers/v1/legalforce/requisition-groups/d2e157cc-120b-4ade-8879-0326c32127bd