Metaの大規模言語モデルを活用した自動単体テストの改善
(arxiv.org)Metaの自動化された単体テスト改善ツール: TestGen-LLM
- Metaが開発したTestGen-LLMは、大規模言語モデル(LLM)を用いて、従来は人手で作成されていたテストを自動的に改善する。
- TestGen-LLMが生成したテストクラスは、元のテストスイートに対して測定可能な改善を保証する一連のフィルターを通過し、LLMのハルシネーション問題を解消した。
- MetaのInstagramおよびFacebook向けプラットフォームで実施したテスト・コンテスト(test-a-thons)におけるTestGen-LLMの導入を説明している。
TestGen-LLMの性能評価
- InstagramのReelsとStories製品に対する評価では、TestGen-LLMのテストケースの75%が正しくビルドされ、57%が信頼性をもって通過し、25%がカバレッジを向上させた。
- MetaのInstagramおよびFacebookのテスト・コンテストでは、TestGen-LLMにより対象クラス全体の11.5%が改善され、Metaのソフトウェアエンジニアは導入のために73%の推奨事項を採用した。
- これは、LLMが生成したコードの産業規模での導入についての初めての報告であり、コード改善に対するこの種の保証が示されたものである。
GN⁺の意見
- TestGen-LLMは、ソフトウェアテストの自動化と品質向上を革新し得るツールであり、大規模言語モデルを活用して既存テストを改善することに成功している。
- このツールは実環境でテストカバレッジを向上させ、信頼性の高いテストケースを生成することで、ソフトウェアエンジニアリングコミュニティに重要な貢献をしている。
- Metaのテスト・コンテストでの成功事例は、TestGen-LLMが実際の製品開発へ統合される可能性を示しており、ソフトウェア開発の効率と安定性を向上させる重要な進展となる。
1件のコメント
Hacker News のコメント
以前勤めていた大手保険会社で、経営陣がコードベース全体のテストカバレッジ 80%を目標に掲げたところ、人々は目標を達成するために Java DTO の getter/setter に無意味な単体テストを書き始めた
当然、開発者は Sonar のカバレッジ測定ルールも変えられず、KPI だけを見ると本来の意図に反する行動を促してしまうことがあるのだと、若手開発者だったころに学んだ
よく設計されたE2E テストシナリオがいくつかあるほうが、ソフトウェア品質にはおそらく良かった
問題は、汚い既存コードが95%のカバレッジで非常によくテストされていたことだった。新しいコードは 100% カバレッジだったが、ずっと短くなったせいで全体のカバレッジはむしろ下がり、通らなかった
残ったのはテストしづらく、テストの意味もあまりない Swing UI コードだけだったので、開発リードは Swing のテストに1〜2週間かける代わりに、既存コードをリポジトリのどこかに残し、テストだけがそのコードを参照するようにした
結局、本番では絶対に呼ばれないデッドコードが数千行、Sonar を満足させるためにリポジトリに残った
結果として、ヘッダーに
static const unsigned ONE = 1;、TWO = 2;、THREE = 3;のような定数が何千個もできることになったhttps://en.m.wikipedia.org/wiki/Mutation_testing
ほぼすべての言語にツールやフレームワークがあり、例として stryker-mutator(C#、TypeScript)、pitest(Java)、mutatest(Python)がある
6年のキャリアの中で、あれほど出来の悪いアプリケーションは初めて見た。スタイルだけでなく、実際に完全に壊れている部分も多かったのに、何が間違っているのか誰も分かっていなかった
Sonar は本当に嫌いだ。脆弱性報告用にだけ使うべきで、変数名を変えろとか「このコード重複はリファクタリングすべきだ」などと言うべきではない。すでに Jira チケットのバックログがあるのだから、何をいつやるべきかまで指示しないでほしい
だが管理者たちはこういう権限ごっこツールが大好きだ
大きな問題は、それを義務化しておきながら、その愚かさを避けるには巨大な官僚的手続きを通らせる点だ。先週も、必須のコード品質ツールが
res.status(200).json()に HSTS ヘッダーがないと文句を言ってきて揉めた手動で設定しても、
app.use(helmet())を使っても文句を言い続け、結局バックエンド全体を単一ファイルに書いてほしいように見えた。実際には HSTS は ingress やロードバランサーで、よりエレガントかつ自動的に処理される誤検知としてマークし、上位管理者に HSTS とは何かを説明して承認を得るのに1〜2週間使うこともできたが、結局レスポンスオブジェクトのプロトタイプに
res.sendJson(data, status = 200)を追加した。明らかに馬鹿げた実装だが、官僚主義の強い分野では、悪いソフトウェアがこうした悪い実装の総和として作られるのだと気づかされた「TestGen-LLMのテストケースの75%が正常にビルドされ、57%が安定して通過し、25%がカバレッジを向上させた」というくだりを見ると、LLM生成テストがバグのある挙動を「公認」してしまう可能性が高そうなのが問題だと思う
特に、すでにテストカバレッジが低いコードベースならなおさらそうなりそう。人間が自分で新しいテストを書く場合、システムが愚かなのかテストが間違っているのかを判断する人がいるという利点がある
少なくとも、こうしたテストは特別なテストフォルダに分離し、相応の疑いを持って扱うべきだ
ただし、カバレッジの良いコードベースは大規模なリファクタリングを回帰なしに安全に行えるようにしてくれるし、バグがあってリファクタリングがそのバグをそのまま保持したとしても有用な性質である
現在の挙動をエンコードするよう設計されたテスト生成ツールの危険は、実際には現在の挙動だけをエンコードしたにすぎないのに、偽の安心感に陥り得る点にある
もしかすると、こういうものを「テスト」と呼ばず、「振る舞いスナップショット」のような名前で呼べば解決するかもしれない。正しい挙動ではなく現在の挙動をキャプチャする、という意味を含めるべきだ
だから、どのシナリオが起きたのかを判断するには、ある程度の人間による監督が常に必要だと思う
こうしたことはあらゆるシステムで起きるし、人々はここでのように自動化レイヤーをもう1つ重ねれば解決すると考えがちである。テストはもともとプログラムが正しく動作するか確認するために発明されたが、それすら自動化すると、同じ問題に、より大きなコード、つまりアサーションではなくテストという形で再び出会うことになる
テストに必要な副次的入力のためのファクトリをどう作るべきかは分からなくても、コード自体がどう動作すべきかは分かっている場合がある
LLMがテストの骨組みを用意し、開発者がビジネスロジックの検証を簡単に書けるようにしてくれるなら、大きなメリットになり得る
ただし、生成されたテストが多くの単体テストのように実装へ過度に結合しているなら、開発速度を落とすことになるだろう。個々のテストを直すのが難しすぎると、大きな変更の際に人々がすべてのテストを削除して再生成する光景まで見られるかもしれない
コードの一部がそのバグに依存している可能性があり、偶然であれ意図的であれそれを直すと、より深刻な問題が起きる可能性がある
もちろん、こうしたテストが実際の要件を確認するテストの代わりになることはない
しかし、低いカバレッジのまま保守モードに入ったレガシーシステムは数え切れないほどあり、そのような場合、現在の挙動を検証するテスト生成は非常に有用である。誰かが変更を加えたときに、残りがそのままであることを確認できるようにしてくれる
PDFを読んでみると、これは「単に」繰り返し通る、つまり不安定ではないテストを生成するもののように見える
主な目的は、既存コードの挙動を固定するテストで回帰テスト群を作ることであり、機能要件を理解して書く開発者テストを置き換えるものではない
ほぼ20年前に勤めていた会社でもAgitarOneを試したが、Javaコードの挙動を探索するテストケースを自動生成してくれるという触れ込みだった。また、通過するテストをほぼ自動で作り、回帰テスト群として使うこともできた
個人的には好きではなかった。あまりに多くのものが生まれ、経営陣はカバレッジが上がれば品質も上がると理解していたからだ。ここでFBが語っているLLMアプローチが当時よりどれほど良いのか気になる
http://www.agitar.com/solutions/products/agitarone.html
LLMが、良いテストは通るという仮定やオラクルに依存せずに実際の正確性を判断できるようになるまでは、ここまで来るのは難しそうだ。プロンプトに何らかの形で挙動の期待値を含める必要があるだろう
テストの価値は、誰かが気にしているものを壊さないことを保証する点にあり、特定の実装の産物にすぎない、ほとんど使われないあらゆるエッジケースの挙動を永遠に固定する点にあるのではない
経験上、テスト作成はたいていコード品質を判断する優れた方法である
テストが複雑だったりカバレッジ達成が難しかったりするなら、テスト対象のコードを改善すべき可能性が高い
低結合・高凝集・低複雑度のコードは、単体テストしやすいはずだ
InstagramのReelsとStories製品評価では、TestGen-LLMのテストケースの75%が正常にビルドされ、57%が安定して通過し、25%がカバレッジを向上させたという
MetaのInstagramとFacebookのテストイベントでは、適用された全クラスの11.5%を改善し、推奨の73%がMetaのソフトウェアエンジニアによって本番デプロイ用に承認されたという
これが良い比率なのかは分からない。受け入れられなかったものが、コードレビューで見つけるような些細なミスだったのか、深刻な問題だったのか、もっと読んでみる必要がある。失敗率25%の人間のエンジニアなら、失敗の種類によってはあまり役に立たないかもしれない
Androidコードの単体テスト生成を自動化するという全体の任務も、良い方向なのか疑問だ。TDD派の人たちは墓の中で、あるいは自宅のベッドで寝返りを打っていそうだ。それでも、背後にただし書きは付けているのだろうとは思う
unlogged.io ではしばらくの間、主力は JUnit テストの自動生成だったが、いくつかの理由であまりうまく普及しなかった。
生成されるテストコードが多すぎて開発者が保守したがらず、実際のシナリオをシミュレートできず、コードカバレッジは虚栄の指標だった。開発者たちは意味のないシナリオで目標を達成する抜け道を見つけていた。
現在は、固有の運用シナリオをすべてシミュレートし、開発者が外部依存をモックした状態でローカルに再生できる ノーコード再生テストを提供しようと取り組んでいる。
ちなみに私は unlogged.io の創業者です。
逆の方向に進みたい。受け入れ基準を入力すると、それを確認するテストを生成し、その後でそのテストを通るコードを生成させたい。
Copilot では限定的に、ときどき似たようなことはできるが、なぜ誰もこの順序に注目していないように感じるのか分からない。
TestGen-LLM は本当に奇妙な産物だ。リファクタリングや書き直しの最初のステップとしては使えそうだが、論文で コードカバレッジを強調しているのは、判断が完全におかしくなっている感じがする。
組織がすでに高いカバレッジを求めて壊れているなら良いかもしれないが、TestGen-LLM はプロジェクトのコードをいかなる形でも良くせず、実際の改善を実装する際の摩擦を増やすだけだろう。
通るかもしれないし通らないかもしれないエッジケースのテストを生成するほうがずっと有用なはずだが、TestGen-LLM はコンパイルエラーと失敗するテストで LLM のゴミをふるい落とすことに依存している。
論文に生成されたテストの例がまったくない点を見ると、これまで見てきた他の LLM 生成コードと同じく素人っぽいのではないかと疑ってしまう。
コードが何をしようとしているのか理解する助けにさえなった。
Meta の社員たちが開発者向け AI を宣伝するために書いた 12 ページの論文だという点は興味深く、サンキー図まで持ち出している。
間違っているかもしれないが、このような形で発表するなら再現可能な情報も提供すべきではないかと思う。
陰謀論ではなく、単に Meta が学習に使うようなレベルのデータは私にはない。何か公開しているのか気になる。
今後、巨大な自動生成テストのコーパスを保守するコストがどれほどになるのか気になる。
テストケースを生成するだけでなく、更新する自動化手法も提供する必要がある。