オックスフォードに拠点を置くDiffblueは、同社のAIがソフトウェア開発において最も重要だが面倒な作業の1つであるユニットテストの作成を自動化すると主張している。
テスト駆動開発(TDD)は、1980年代後半にSmalltalk用のユニットテストフレームワークを作成したケント・ベックによって発明された(あるいは彼自身の言葉を借りれば再発見された)手法です。ユニットテストを用いてコードを実行し、出力が期待通りであることを確認するという考え方は現在、ベストプラクティスとして広く受け入れられています。
ユニットテストは、以前は正常に動作していたコードにバグが入り込むこと(リグレッション)を防ぐのに役立ちます。また、CI/CD(継続的インテグレーションと継続的デリバリー)においても重要な役割を担っています。これは、開発者がコードを追加または変更した後もアプリケーションやサービスが引き続き動作するという確信を得られるためです。そのため、厳密なユニットテストなしに、迅速なリリース(頻繁なリリース)を維持することは困難です。人気の高いSQLiteデータベースエンジンでは、エンジン本体のコードの640倍ものテストコードが使用されています。
ユニットテストを書くことは重要かもしれませんが、機能を追加することほど面白くはありません。「退屈で単調な作業です。とても重要なのですが、チームが時間的なプレッシャーにさらされると真っ先に削られてしまいます」と、DiffblueのCEOであるマシュー・ロッジ氏はThe Register紙に語っています。「人間はユニットテストがあまり得意ではなく、退屈なので多くのミスを犯してしまいます。」
隠れてください...
Diffblueは、AIを用いてテストを自動作成する研究を経て、オックスフォード大学からスピンアウトしました。ユニットテストを生成するツールは既に数多く存在しますが、一般的にはテンプレートベースで、開発者がロジックを追加する必要があります。一方、DiffblueのCoverはすべてを自動作成します。「コンパイルしてパスするユニットテスト一式を作成します。これは、プログラムの現在の動作を反映する完全なユニットテストスイートです。そのため、変更を加えた際に、テストの動作から変更内容を把握し、リグレッション(回帰)を検知することができます」とロッジ氏は述べています。
Diffblue Cover は、サンプル Spring Boot アプリケーション Petclinic で AI 生成テストを実行しています (クリックして拡大)
Coverは無料のコミュニティエディションとしてリリースされました。Javaのみで動作し、IDEとの統合はIntelliJ IDEAのみですが、有料版にはコマンドラインオプションも用意されています。
「小さな会社として、まずは一つのことをしっかりとやり遂げたいと思っています」とロッジ氏は語った。「コア技術は言語に依存しないため、プログラムを分析する際には、推論可能なプログラムモデルを構築し、テストを実行します。そして、テストの汎用的な表現を再び使用し、それをJavaに翻訳します。」
ロッジ氏は、JavaScript と Python は一般的な要望であり、すでに初期のアルファ版がリリースされている Visual Studio Code のサポートも同様であると述べた。
じゃあ、一緒に遊ぼうよ
Spring Boot Petclinic サンプルに、ペットとその飼い主のデータベースを含む新しいメソッドを作成しました。メソッドは でHasPet()
、飼い主が実際にペットを飼っているかどうかを判定します。メソッドを右クリックし、「テストの記述」を選択すると、Cover によって 2 つのテストメソッドが生成されます。1 つ目のテストメソッドは、新しい飼い主を作成しますがペットは作成しません。メソッドを呼び出して、結果が false であることをアサートします。2 つ目のテストメソッドは、新しい飼い主とペットを作成し、ペットを飼い主に割り当て、メソッドを呼び出して true であることをアサートします。素晴らしいですね。
しかし、問題がありました。修正したHasPet()
結果、バグが発生してしまいました。本来は偽であるべきところを真が返し、逆もまた同様です。そこで、Coverに新しいテストを生成するように指示しました。Coverはコードの意図ではなく、実際に何を行っているかだけを認識していたため、新しいテストは成功しました。とはいえ、Coverは古いテストをそのまま残し、それらは当然失敗しました。つまり、問題があるという手がかりはあったということです。もし元のコードにバグを記述していたら、Coverのテストは役に立たなかったでしょう。開発者がテストコードを検査し、そのアサーションに疑問を抱かない限りは。
ロッジ氏はこの問題を認め、次のように語った。「コードにはそもそもバグがある可能性があり、コード内の現在のロジックが正しいかどうかは判断できません。プログラマーの意図がわからないためであり、現時点では機械が理解できる方法で意図を表現するよい方法はありません。」
「これは、一般的に、ほとんどのお客様が抱えている問題ではありません。ほとんどのお客様はユニットテストをほとんど実施しておらず、通常はプロセスの最後に機能的なエンドツーエンドテストを実行する一連のテストを実施しています。」
ロッジ氏の主張は、動作するアプリケーションから始めて、Coverにテストを任せれば、高速デリバリーに適したコードベースが完成するというものだ。「当社の顧客は単体テストを全く実施していないか、カバレッジが5~10%程度しかない。彼らの問題はソフトウェアをテストできないことではなく、テストはできるのだ。リリース直前にエンドツーエンドテストを実行できる。彼らが持っていないのは、CI/CDパイプラインを実行し、毎日ソフトウェアをリリースできるようにする単体テストだ。つまり、当社の顧客は一般的に、年に2回ソフトウェアをリリースできるような企業なのだ。」
Diffblue Cover で Petclinic アプリケーション用のテストを作成 (クリックして拡大)
ユニットテストが不足している理由は、時間的なプレッシャーか、あるいは歴史的な事情によるものかもしれません。「ほとんどの組織は既存のアプリケーションをベースに構築しており、銀行のような組織にとってこれが最大の課題です。銀行を動かすJavaコードはすべてあり、プロセスの最後に実行できるテストがあるので、それを出荷する方法はありますが、コミットごとに実行できるテストがないのです。」
Diffblue Coverはどのように機能するのでしょうか?「静的解析と動的解析を組み合わせたものです」とロッジ氏は言います。「まず、良いと思われるテストを作成し、それをコードに対して実行してメソッドの挙動を観察します。実行することで、メソッドの動作、副作用、戻り値を確認できます。そして、生成したテストよりも優れたテストを探します。そして、可能性のあるテストケースの空間を確率的に探索します。」
関心のある方は、Diffblue サイトでこのプロセスの背景にある研究の一部を確認できます。
Diffblueはゴールドマン・サックスとの提携から生まれたため、銀行業界に特化しています。「ゴールドマン・サックスは当社の技術に非常に興味を持っていたので、当社に協力してくれました。ゴールドマンは製品の開発を支援し、基本的にゴールドマンの協力を得て最初のバージョンを開発しました」とロッジ氏は語ります。「現在公開されているコミュニティ・エディションは、最初の経験から学んだすべての成果を反映したバージョン2です。このようなツールはかつてありませんでした。コミュニティ・エディションの目的は、このツールの機能を人々に無料で体験してもらうことです。」
「完全なモックを使ったテストを約600ミリ秒で作成できます。つまり、人間よりも10~100倍速くテストを作成できるということです。」
Cover は開発者のコードを実行するのに非常に役立ちますが、残念ながら意図したとおりに動作しているかどうかは人間だけが知ることができます。®