15
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

NRI OpenStandiaAdvent Calendar 2024

Day 10

[検証] Amazon Q Developerのドキュメント&ユニットテスト自動生成機能はどこまで手動作成クオリティに近づくのか

Last updated at Posted at 2024-12-09

はじめに

こちらはNRI OpenStandia Advent Calendar 2024の10日目の記事です。
AWS re:Invent 2024にて、Amazon Q Developerのアップデートとして「コードに基づいたドキュメント自動生成」機能と「コードに基づいたユニットテスト自動生成」機能が発表されました。

Amazon Q Developerは、AWS社のコードやドキュメントをもとに学習が行われています。つまり、「自動生成されるドキュメント」と「自動生成されるユニットテスト」はAWS本家が手動作成しているドキュメントやユニットテストと同じようなクオリティになるのではないでしょうか。

そこで、今回はAWS社から出しているOSSを題材として、どのようなドキュメントやユニットテストが自動生成されていくかを見ていこうと思います。

Amazon Q Developerとは

Amazon Q Developerは運用開発者がVSCodeやIntelliJ等のコードエディタを用いてコーディングする際に、生成AIによるアシストをしてくれるツールです。

アシスト例はこちらです。

  • コーディング時に、リアルタイムでコードを補完
  • チャット上で自然言語(例:日本語、英語)を用いてQA回答
  • /devコマンドをトリガーとして、リアルタイムで実装コードを提案
  • /transformコマンドをトリガーとして、Javaのレガシーコードのアップデート方法を提示
  • /reviewコマンドをトリガーとして、コードレビュー機能にて脆弱性やリスクを特定し、緩和策も提示
  • /docコマンドをトリガーとして、ドキュメントを自動生成(※本記事での検証1)
  • /testコマンドをトリガーとして、ユニットテストを自動生成(※本記事の検証2)

検証

検証に用いるAWS本家のソースコード

Java検証用にServerless Java container、Python検証用にaws-cliをピックアップしました。

検証方法

  1. 該当コードをcloneします
  2. 自動生成する予定のファイルを全部削除します
    • 検証1:README、フォルダ内に存在するドキュメント(例:docフォルダ配下すべて)
    • 検証2:フォルダ内に存在するテスト(例:testフォルダ配下すべて)
  3. /docコマンド or /testコマンドを実行します
    • /docコマンドはコマンドを叩いたあとにREADMEを自動生成したいリポジトリを選択します
    • /testコマンドはユニットテストを自動作成したいファイルをあらかじめアクティブ状態にしてからコマンドを叩く必要があります

検証1:/docコマンドをトリガーとして、ドキュメントを自動生成

Serverless Java containerの検証結果

Serverless Java containerの実行結果はこちらです。公式のREADMEとは異なる全く異なるアウトプットであることから、「Amazon Q Developerは過学習していない(個別最適化されないように、大量のデータを学習している)」ということがわかります。

image.png

中身を詳しく見ていきます。まずREADMEの目次構成は下記のようになっていました。READMEの構成として、存在すると便利な項目が綺麗に並んでおり、READMEとしての有用性が高くなっております。

README.md の目次構成
AWS Serverless Java Container(タイトル)
├ Repository Structure(リポジトリ内のモジュール構成)
├ Usage Instructions(使い方)
│├ Installation(インストール方法)
│├ Getting Started(インストール後の使い方)
│├ Configuration(使う際の設定について)
│├ Common Use Cases(主なユースケース)
│├ Testing(テスト実行方法)
│└ Troubleshooting(トラブルシューティング)
├ Data Flow(データの流れ)
├ Deployment(デプロイ方法)
└ Infrastructure(インフラ構成)

それぞれの項目も、コマンドベースで丁寧に記載がされていました。また、内容もおおむね「一般的に正しいことが多い」回答となっておりました。

例えば、トラブルシューティングの章は一般的な対応方法が記載されています。インストールの章も同じくです。
なお、インストールバージョンに関しては、「Prerequisites」で指定されているバージョンよりも古いバージョン(例:Java17)も本OSSは利用可能と思われます。と言いますのも、本OSSはgithubのワークフロー設定(.github/workflows/continuous-integration-workflow.yml)にてJava17を指定しています。

ただ最新LTSであるJava21を推奨しているのは個人的には悪くないと思います。アシスタントする生成AI側で明確に推奨バージョンを判別できない場合、一般的には新しいLTSを使う方が推奨されるため、回答として「明確な」間違いとなる可能性が低いためです。

README.md(一部抜粋:Installation)
### Installation

Prerequisites:
- Java 21 or later
- Maven 3.6.3 or later
- AWS CLI configured with appropriate credentials

To install the AWS Serverless Java Container, clone the repository and build the project:

---
git clone https://github.com/aws/serverless-java-container.git
cd serverless-java-container
mvn clean install
---
README.md(一部抜粋:Troubleshooting)
### Troubleshooting

Common issues and solutions:

1. ClassNotFoundException:
   - Ensure all dependencies are correctly specified in your `pom.xml` file.
   - Check that the `Handler` property in your `template.yml` file points to the correct class.

2. API Gateway errors:
   - Verify that your API routes are correctly defined in your application code.
   - Check the CloudWatch logs for your Lambda function for any error messages.

3. Performance issues:
   - Consider using the `async` initialization option for faster cold starts.
   - Optimize your application code and reduce the number of dependencies.

aws-cliの検証結果

もう一つの検証対象であるaws-cliも見ていきます。READMEの目次構成は下記の通りです。

この目次は、Serverless Java containerのREADME自動生成の結果と完全一致はしていないものの、かなり似ております。このことから、裏側で動いている生成AI側である程度READMEの目次フォーマットを決めていることが推測できます。

README.md の目次構成
AWS Command Line Interface (CLI)(タイトル)
├ Repository Structure(リポジトリ内のフォルダ構成、主要なファイル)
├ Usage Instructions(使い方)
│├ Installation(インストール方法)
│├ Configuration(使う際の設定について)
│├ Basic Usage(インストール後の基本的な使い方)
│└ Getting Help(使い方のヘルプコマンド)
├ Data Flow(データの流れ)
├ Deployment(デプロイされている形式)
├ Infrastructure(インフラ構成)
├ Testing & Quality(テスト方法)
├ Troubleshooting(トラブルシューティング)
└ Performance Optimization(パフォーマンスの最適化)

記載内容もおおむね正しいです。Repository Structureは検証のためにdocフォルダを削除しているためそれが記載されていないのは想定通りです。ドキュメント以外のフォルダは主要なものを問題なくピックアップできております。(awscliフォルダ配下にtopicsフォルダがあることを紹介できておりませんが、これは後述する「READMEの修正」で修正可能な範囲です。)

README.md(一部抜粋:Repository Structure)
## Repository Structure

The repository is organized as follows:

- `aws-cli/`: Main directory containing the AWS CLI source code
  - `awscli/`: Core AWS CLI implementation
    - `customizations/`: Custom commands and behaviors for specific AWS services
    - `data/`: Configuration data files
    - `examples/`: Example files and templates
  - `bin/`: Executable scripts
  - `scripts/`: Utility scripts for development and testing
  - `tests/`: Test suite for the AWS CLI

Key Files:
- `aws-cli/awscli/__main__.py`: Entry point for the AWS CLI
- `aws-cli/awscli/clidriver.py`: Main driver for the CLI functionality
- `aws-cli/setup.py`: Setup script for installing the AWS CLI

また、InstallationにおいてPythonのバージョンが3.8以上である必要があることは、setup.pyの記載とも一致します。

image.png

README.md(一部抜粋:Installation)
### Installation

1. Ensure you have Python 3.8 or later installed.
2. Install the AWS CLI using pip:

---
pip install awscli
---

実際のところは、aws-cliのインストール方法は多岐にわたります。これらの情報も加味するには、別途手動で追加することになりそうです。

なお、ここまで初回生成のREADMEを見ていきましたが、このREADMEはプロンプト指示をだすことによる修正が可能です。
例えば、セクションの追加や削除、特定の文章自体の修正が可能です。この際、変更したいセクションや追加削除したいコンテンツ、文章の修正方針は明確に記述する必要があります。また、参照する必要があるものは、参照先がコードである必要があります。

また、READMEをより良いものとするためにAWS公式からベストプラクティスが提供されています。
https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/doc-generation-best-practices.html

検証2:/testコマンドをトリガーとして、ユニットテストを自動生成

/testコマンドを実行すると下記のような画面を見ることができます。なお、2024/12現在はJavaとPythonのみが対応となっております。ここでは文量の都合でaws-cliの検証結果のみ紹介します。

image.png

aws-cliの検証結果

下記ファイルの単体テストを行いました。
https://github.com/aws/aws-cli/blob/develop/awscli/customizations/s3/fileinfo.py

該当ファイルには、下記4つのメソッドがあります。

  • __init__(self, src, dest, compare_key, size, last_update, src_type, dest_type, operation_name, client, parameters, source_client, is_stream, associated_response_data)
  • is_glacier_compatible(self)
  • _is_glacier_object(self, response_data)
  • _is_restored(self, response_data)

生成されたテストケース一覧は下記の通りです。対象メソッド1つ1つに対して、正常ケースだけでなく異常ケースもしっかり検討されており、パターンも多く揃っております。(※番号1と3でまったく同じで何も記載のないテストが生成されていますが、この程度の余分なテストは削除する手間もたいしてないので、問題ないかと思っております。)

テストメソッド テストの説明 テスト対象メソッド
1 test__is_glacier_object_1 既存のテスト(変更なし) _is_glacier_object
2 test__is_glacier_object_2 非Glacierオブジェクトの場合にFalseを返すことをテスト _is_glacier_object
3 test__is_glacier_object_3 既存のテスト(変更なし) _is_glacier_object
4 test__is_restored_with_case_sensitive_restore_value 大文字小文字を区別するRestore値でのテスト _is_restored
5 test__is_restored_with_empty_input 空の入力での_is_restoredメソッドのテスト _is_restored
6 test__is_restored_with_empty_restore_value 空のRestore値での_is_restoredメソッドのテスト _is_restored
7 test__is_restored_with_incorrect_type 不正な入力タイプでの_is_restoredメソッドのテスト _is_restored
8 test__is_restored_with_invalid_restore_value 無効なRestore値での_is_restoredメソッドのテスト _is_restored
9 test__is_restored_with_missing_restore_key Restoreキーが欠落している場合の_is_restoredメソッドのテスト _is_restored
10 test__is_restored_with_none_input None入力での_is_restoredメソッドのテスト _is_restored
11 test__is_restored_with_ongoing_request 進行中のリクエストでの_is_restoredメソッドのテスト _is_restored
12 test__is_restored_with_partial_restore_value 部分的なRestore値での_is_restoredメソッドのテスト _is_restored
13 test_init_with_all_parameters すべてのパラメータを指定してFileInfoを初期化するテスト __init__
14 test_init_with_default_parameters デフォルトパラメータでのFileInfo初期化テスト __init__
15 test_init_with_empty_src 空のsrcパラメータでの初期化テスト __init__
16 test_init_with_invalid_associated_response_data 無効なassociated_response_dataでの初期化テスト __init__
17 test_init_with_invalid_dest_type 無効なdest_typeパラメータでの初期化テスト __init__
18 test_init_with_invalid_is_stream 無効なis_streamパラメータでの初期化テスト __init__
19 test_init_with_invalid_last_update 無効なlast_updateパラメータでの初期化テスト __init__
20 test_init_with_invalid_operation_name 無効なoperation_nameパラメータでの初期化テスト __init__
21 test_init_with_invalid_parameters_type 無効なparameters型での初期化テスト __init__
22 test_init_with_invalid_src_type 無効なsrc_typeパラメータでの初期化テスト __init__
23 test_init_with_negative_size 負のsizeパラメータでの初期化テスト __init__
24 test_init_with_parameters パラメータを指定してFileInfoを初期化するテスト __init__
25 test_is_glacier_compatible_1 Glacierオブジェクトのダウンロード操作の互換性テスト is_glacier_compatible
26 test_is_glacier_compatible_3 Glacierオブジェクトの削除操作の互換性テスト is_glacier_compatible
27 test_is_glacier_compatible_deep_archive_object Deep Archiveオブジェクトの互換性テスト is_glacier_compatible
28 test_is_glacier_compatible_glacier_object_copy Glacierオブジェクトのコピー操作の互換性テスト is_glacier_compatible
29 test_is_glacier_compatible_glacier_object_download Glacierオブジェクトのダウンロード操作の互換性テスト is_glacier_compatible
30 test_is_glacier_compatible_glacier_object_move_local_source ローカルソースのGlacierオブジェクトの移動操作の互換性テスト is_glacier_compatible
31 test_is_glacier_compatible_glacier_object_move_s3_source S3ソースのGlacierオブジェクトの移動操作の互換性テスト is_glacier_compatible
32 test_is_glacier_compatible_glacier_upload Glacierオブジェクトのアップロード操作の互換性テスト is_glacier_compatible
33 test_is_glacier_compatible_invalid_storage_class 無効なストレージクラスでの互換性テスト is_glacier_compatible
34 test_is_glacier_compatible_move_from_s3_glacier S3 Glacierからの移動操作の互換性テスト is_glacier_compatible
35 test_is_glacier_compatible_no_associated_response_data 関連レスポンスデータがない場合の互換性テスト is_glacier_compatible
36 test_is_glacier_compatible_non_glacier_object 非Glacierオブジェクトの互換性テスト is_glacier_compatible
37 test_is_glacier_compatible_non_glacier_object_2 別の非Glacierオブジェクトの互換性テスト is_glacier_compatible
38 test_is_glacier_compatible_restored_glacier_object 復元されたGlacierオブジェクトの互換性テスト is_glacier_compatible
39 test_is_glacier_object_case_sensitivity ストレージクラスの大文字小文字の区別テスト _is_glacier_object
40 test_is_glacier_object_copy_operation Glacierオブジェクトのコピー操作のテスト _is_glacier_object
41 test_is_glacier_object_deep_archive Deep Archiveストレージクラスの判定テスト _is_glacier_object
42 test_is_glacier_object_empty_input 空の入力での_is_glacier_objectメソッドのテスト _is_glacier_object
43 test_is_glacier_object_incorrect_type 不正な入力タイプでの_is_glacier_objectメソッドのテスト _is_glacier_object
44 test_is_glacier_object_invalid_storage_class 無効なストレージクラスでの_is_glacier_objectメソッドのテスト _is_glacier_object
45 test_is_glacier_object_missing_storage_class ストレージクラスが欠落している場合の_is_glacier_objectメソッドのテスト _is_glacier_object
46 test_is_glacier_object_restored_glacier 復元されたGlacierオブジェクトの_is_glacier_objectメソッドのテスト _is_glacier_object
47 test_is_glacier_object_returns_false_for_empty_response_data 空のレスポンスデータでの_is_glacier_objectメソッドのテスト _is_glacier_object
48 test_is_glacier_object_returns_false_for_non_glacier_storage_class 非Glacierストレージクラスでの_is_glacier_objectメソッドのテスト _is_glacier_object
49 test_is_glacier_object_returns_false_for_none_response_data Noneレスポンスデータでの_is_glacier_objectメソッドのテスト _is_glacier_object
50 test_is_glacier_object_returns_false_for_restored_glacier_object 復元されたGlacierオブジェクトでの_is_glacier_objectメソッドのテスト _is_glacier_object
51 test_is_glacier_object_returns_true_for_deep_archive_storage_class Deep Archiveストレージクラスでの_is_glacier_objectメソッドのテスト _is_glacier_object
52 test_is_glacier_object_returns_true_for_glacier_storage_class Glacierストレージクラスでの_is_glacier_objectメソッドのテスト _is_glacier_object
53 test_is_glacier_object_with_no_response_data レスポンスデータがない場合の_is_glacier_objectメソッドのテスト _is_glacier_object
54 test_is_restored_when_object_is_not_restored オブジェクトが復元されていない場合の_is_restoredメソッドのテスト _is_restored
55 test_is_restored_when_object_is_restored オブジェクトが復元された場合の_is_restoredメソッドのテスト _is_restored
56 test_is_restored_when_restore_info_is_missing 復元情報が欠落している場合の_is_restoredメソッドのテスト _is_restored

テストメソッドを一部抜粋します。こちらの中身のロジックも問題なさそうです。

test_fileinfo.py(一部抜粋:6 空のRestore値での_is_restoredメソッドのテスト)
    def test__is_restored_with_empty_restore_value(self):
        """
        Test _is_restored method with empty Restore value
        """
        file_info = FileInfo(src='test')
        response_data = {'Restore': ''}
        assert not file_info._is_restored(response_data)
test_fileinfo.py(一部抜粋:51 Deep Archiveストレージクラスでの_is_glacier_objectメソッドのテスト)
    def test_is_glacier_object_returns_true_for_deep_archive_storage_class(self):
        """
        Test that _is_glacier_object returns True for a DEEP_ARCHIVE storage class
        that is not restored.
        """
        file_info = FileInfo(src='dummy_src')
        response_data = {
            'StorageClass': 'DEEP_ARCHIVE',
            'Restore': 'ongoing-request="true"'
        }
        
        result = file_info._is_glacier_object(response_data)
        
        assert result == True

なお、本家のtest_fileinfo.pyファイルは下記の通りです。本家のユニットテストコードはより見やすいですね。とはいえ自動生成も健闘しているとは思うので、さらなる発展を期待します。
https://github.com/aws/aws-cli/blob/develop/tests/unit/customizations/s3/test_fileinfo.py

さいごに

予想よりもドキュメント自動作成、ユニットテスト自動生成のクオリティが高かったため、活用できる箇所にはぜひ活用していきたいなと思いました。

また、ドキュメント自動生成にはサービスクォータがありますのでご注意ください!

(参考)サービスクォータ

  • 既存のREADMEの最大サイズ:15KB
  • READMEを作成するプロジェクトに格納されているコードサイズ:200MB(非圧縮の場合)、50MB(圧縮の場合)
  • タスクごとのドキュメント生成数:3
15
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?