Cookie の設定を選択する

当社は、当社のサイトおよびサービスを提供するために必要な必須 Cookie および類似のツールを使用しています。当社は、パフォーマンス Cookie を使用して匿名の統計情報を収集することで、お客様が当社のサイトをどのように利用しているかを把握し、改善に役立てています。必須 Cookie は無効化できませんが、[カスタマイズ] または [拒否] をクリックしてパフォーマンス Cookie を拒否することはできます。

お客様が同意した場合、AWS および承認された第三者は、Cookie を使用して便利なサイト機能を提供したり、お客様の選択を記憶したり、関連する広告を含む関連コンテンツを表示したりします。すべての必須ではない Cookie を受け入れるか拒否するには、[受け入れる] または [拒否] をクリックしてください。より詳細な選択を行うには、[カスタマイズ] をクリックしてください。

ユニットテスト

フォーカスモード
ユニットテスト - AWS SDK for Rust

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

AWS SDK for Rust プロジェクトにユニットテストを実装する方法は多数ありますが、いくつかの方法をお勧めします。

  • mockall クレートautomockから を使用して、テストを作成して実行します。

  • AWS Smithy ランタイムの StaticReplayClientを使用して、通常は によって使用される標準 HTTP クライアントの代わりに使用できるフェイク HTTP クライアントを作成します AWS のサービス。このクライアントは、ネットワーク経由でサービスと通信するのではなく、指定した HTTP レスポンスを返します。これにより、テスト目的で既知のデータがテスト用に取得されます。

モコールを使用してモックを自動的に生成する

mockall クレート automockの一般的な を使用して、テストに必要なモック実装の大部分を自動的に生成できます。

この例では、 というカスタムメソッドをテストしますdetermine_prefix_file_size()。このメソッドは、Amazon S3 を呼び出すカスタムlist_objects()ラッパーメソッドを呼び出します。をモックすることでlist_objects()、Amazon S3 に実際に連絡することなくdetermine_prefix_file_size()メソッドをテストできます。

  1. プロジェクトディレクトリのコマンドプロンプトで、依存関係としてmockall木箱を追加します。

    $ cargo add mockall

    これにより、 Cargo.toml ファイルの [dependencies]セクションに木箱が追加されます。

  2. mockall 木箱からautomockモジュールを含めます。

    テスト AWS のサービス する に関連する他のライブラリ、この場合は Amazon S3 も含めます。

    use aws_sdk_s3 as s3; #[allow(unused_imports)] use mockall::automock; use s3::operation::list_objects_v2::{ListObjectsV2Error, ListObjectsV2Output};
  3. 次に、アプリケーションの Amazon S3 ラッパー構造の 2 つの実装のうちどれを使用するかを決定するコードを追加します。

    • ネットワーク経由で Amazon S3 にアクセスするために書き込まれた実際のもの。

    • によって生成されたモック実装mockall

    この例では、選択した名前に が付けられますS3。選択は、 test 属性に基づいて条件付きです。

    #[cfg(test)] pub use MockS3Impl as S3; #[cfg(not(test))] pub use S3Impl as S3;
  4. S3Impl 構造体は、実際に にリクエストを送信する Amazon S3 ラッパー構造の実装です AWS。

    • テストが有効になっている場合、リクエストはモックに送信され、モックに送信されないため、このコードは使用されません AWS。dead_code 属性は、S3Implタイプが使用されていない場合、問題を報告しないように linter に指示します。

    • 条件付き は、テストが有効になっている場合、 automock 属性を設定する必要がある#[cfg_attr(test, automock)]ことを示します。これにより、 という名前の のモックを生成するmockallように に指示S3ImplしますMockS3Impl

    • この例では、 list_objects()メソッドはモックする呼び出しです。 automockは自動的に expect_list_objects()メソッドを作成します。

    #[allow(dead_code)] pub struct S3Impl { inner: s3::Client, } #[cfg_attr(test, automock)] impl S3Impl { #[allow(dead_code)] pub fn new(inner: s3::Client) -> Self { Self { inner } } #[allow(dead_code)] pub async fn list_objects( &self, bucket: &str, prefix: &str, continuation_token: Option<String>, ) -> Result<ListObjectsV2Output, s3::error::SdkError<ListObjectsV2Error>> { self.inner .list_objects_v2() .bucket(bucket) .prefix(prefix) .set_continuation_token(continuation_token) .send() .await } }
  5. という名前のモジュールでテスト関数を作成しますtest

    • 条件付き は、 test 属性が の場合、 がテストモジュールを構築mockallする必要がある#[cfg(test)]ことを示しますtrue

    #[cfg(test)] mod test { use super::*; use mockall::predicate::eq; #[tokio::test] async fn test_single_page() { let mut mock = MockS3Impl::default(); mock.expect_list_objects() .with(eq("test-bucket"), eq("test-prefix"), eq(None)) .return_once(|_, _, _| { Ok(ListObjectsV2Output::builder() .set_contents(Some(vec![ // Mock content for ListObjectsV2 response s3::types::Object::builder().size(5).build(), s3::types::Object::builder().size(2).build(), ])) .build()) }); // Run the code we want to test with it let size = determine_prefix_file_size(mock, "test-bucket", "test-prefix") .await .unwrap(); // Verify we got the correct total size back assert_eq!(7, size); } #[tokio::test] async fn test_multiple_pages() { // Create the Mock instance with two pages of objects now let mut mock = MockS3Impl::default(); mock.expect_list_objects() .with(eq("test-bucket"), eq("test-prefix"), eq(None)) .return_once(|_, _, _| { Ok(ListObjectsV2Output::builder() .set_contents(Some(vec![ // Mock content for ListObjectsV2 response s3::types::Object::builder().size(5).build(), s3::types::Object::builder().size(2).build(), ])) .set_next_continuation_token(Some("next".to_string())) .build()) }); mock.expect_list_objects() .with( eq("test-bucket"), eq("test-prefix"), eq(Some("next".to_string())), ) .return_once(|_, _, _| { Ok(ListObjectsV2Output::builder() .set_contents(Some(vec![ // Mock content for ListObjectsV2 response s3::types::Object::builder().size(3).build(), s3::types::Object::builder().size(9).build(), ])) .build()) }); // Run the code we want to test with it let size = determine_prefix_file_size(mock, "test-bucket", "test-prefix") .await .unwrap(); assert_eq!(19, size); } }
    • 各テストではlet mut mock = MockS3Impl::default();、 を使用して のmockインスタンスを作成しますMockS3Impl

    • これは、モックの expect_list_objects()メソッド ( によって自動的に作成されたautomock) を使用して、list_objects()メソッドがコードの他の場所で使用されたときの期待される結果を設定します。

    • 期待値が確立されたら、これらを使用して を呼び出して関数をテストしますdetermine_prefix_file_size()。返された値は、アサーションを使用して正しいことを確認するためにチェックされます。

  6. determine_prefix_file_size() 関数は Amazon S3 ラッパーを使用してプレフィックスファイルのサイズを取得します。

    #[allow(dead_code)] pub async fn determine_prefix_file_size( // Now we take a reference to our trait object instead of the S3 client // s3_list: ListObjectsService, s3_list: S3, bucket: &str, prefix: &str, ) -> Result<usize, s3::Error> { let mut next_token: Option<String> = None; let mut total_size_bytes = 0; loop { let result = s3_list .list_objects(bucket, prefix, next_token.take()) .await?; // Add up the file sizes we got back for object in result.contents() { total_size_bytes += object.size().unwrap_or(0) as usize; } // Handle pagination, and break the loop if there are no more pages next_token = result.next_continuation_token.clone(); if next_token.is_none() { break; } } Ok(total_size_bytes) }

タイプS3は、ラップされた SDK for Rust 関数を呼び出して、HTTP リクエストを行うMockS3Implときに S3Implと の両方をサポートするために使用されます。によって自動的に生成されたモックは、テストが有効になっているときにテストの失敗mockallを報告します。

これらの例の完全なコードは、GitHub で確認できます。 GitHub

静的再生を使用して HTTP トラフィックをシミュレートする

aws-smithy-runtime クレートには、 というテストユーティリティクラスが含まれていますStaticReplayClient。この HTTP クライアントクラスは、 AWS のサービス オブジェクトの作成時にデフォルトの HTTP クライアントの代わりに指定できます。

を初期化するときはStaticReplayClient、HTTP リクエストとレスポンスのペアのリストをReplayEventオブジェクトとして指定します。テストの実行中に、各 HTTP リクエストが記録され、クライアントはイベントリストReplayEventの次の にある次の HTTP レスポンスを HTTP クライアントのレスポンスとして返します。これにより、既知のデータを使用し、ネットワーク接続なしでテストを実行できます。

静的再生の使用

静的再生を使用するには、ラッパーを使用する必要はありません。代わりに、テストで使用するデータに対する実際のネットワークトラフィックがどのようになるかを判断し、SDK が AWS のサービス クライアントからリクエストを発行するたびにStaticReplayClient使用するトラフィックデータを に提供します。

注記

予想されるネットワークトラフィックを収集するには、 AWS CLI や多数のネットワークトラフィックアナライザー、パケットスニッファツールなど、いくつかの方法があります。

  • 予想される HTTP リクエストと返されるレスポンスを指定するReplayEventオブジェクトのリストを作成します。

  • 前のステップで作成した HTTP トランザクションリストStaticReplayClientを使用して を作成します。

  • AWS クライアントの設定オブジェクトを作成し、 をConfigオブジェクトの StaticReplayClientとして指定しますhttp_client

  • 前のステップで作成した設定を使用して、 AWS のサービス クライアントオブジェクトを作成します。

  • を使用するように設定されたサービスオブジェクトを使用して、テストするオペレーションを実行しますStaticReplayClient。SDK が API リクエストを送信するたびに AWS、リスト内の次のレスポンスが使用されます。

    注記

    送信されたリクエストがReplayEventオブジェクトのベクトルのレスポンスと一致しない場合でも、リスト内の次のレスポンスは常に返されます。

  • 必要なリクエストがすべて実行されたら、 StaticReplayClient.assert_requests_match()関数を呼び出して、SDK によって送信されたリクエストがReplayEventオブジェクトのリスト内のリクエストと一致することを確認します。

前の例で同じdetermine_prefix_file_size()関数のテストを見てみましょう。ただし、モックの代わりに静的再生を使用します。

  1. プロジェクトディレクトリのコマンドプロンプトで、依存関係としてaws-smithy-runtime木箱を追加します。

    $ cargo add aws-smithy-runtime --features test-util

    これにより、 Cargo.toml ファイルの [dependencies]セクションに木箱が追加されます。

  2. ソースファイルに、必要なaws_smithy_runtimeタイプを含めます。

    use aws_smithy_runtime::client::http::test_util::{ReplayEvent, StaticReplayClient}; use aws_smithy_types::body::SdkBody;
  3. テストは、テスト中に実行される各 HTTP トランザクションを表すReplayEvent構造の作成から始まります。各イベントには、HTTP リクエストオブジェクトと、 が AWS のサービス 通常応答する情報を表す HTTP レスポンスオブジェクトが含まれます。これらのイベントは、 への呼び出しに渡されますStaticReplayClient::new()

    let page_1 = ReplayEvent::new( http::Request::builder() .method("GET") .uri("https://test-bucket.s3.us-east-1.amazonaws.com/?list-type=2&prefix=test-prefix") .body(SdkBody::empty()) .unwrap(), http::Response::builder() .status(200) .body(SdkBody::from(include_str!("./testing/response_multi_1.xml"))) .unwrap(), ); let page_2 = ReplayEvent::new( http::Request::builder() .method("GET") .uri("https://test-bucket.s3.us-east-1.amazonaws.com/?list-type=2&prefix=test-prefix&continuation-token=next") .body(SdkBody::empty()) .unwrap(), http::Response::builder() .status(200) .body(SdkBody::from(include_str!("./testing/response_multi_2.xml"))) .unwrap(), ); let replay_client = StaticReplayClient::new(vec![page_1, page_2]);

    結果は に保存されますreplay_client。これは、クライアントの設定で指定することで SDK for Rust で使用できる HTTP クライアントを表します。

  4. Amazon S3 クライアントを作成するには、クライアントクラスの from_conf()関数を呼び出して、設定オブジェクトを使用してクライアントを作成します。

    let client: s3::Client = s3::Client::from_conf( s3::Config::builder() .behavior_version(BehaviorVersion::latest()) .credentials_provider(make_s3_test_credentials()) .region(s3::config::Region::new("us-east-1")) .http_client(replay_client.clone()) .build(), );

    設定オブジェクトはビルダーの http_client()メソッドを使用して指定され、認証情報は credentials_provider()メソッドを使用して指定されます。認証情報は、偽の認証情報構造を返make_s3_test_credentials()す という関数を使用して作成されます。

    fn make_s3_test_credentials() -> s3::config::Credentials { s3::config::Credentials::new( "ATESTCLIENT", "astestsecretkey", Some("atestsessiontoken".to_string()), None, "", ) }

    これらの認証情報は実際には送信されないため、有効である必要はありません AWS。

  5. テストが必要な 関数を呼び出してテストを実行します。この例では、その関数の名前は ですdetermine_prefix_file_size()。最初のパラメータは、リクエストに使用する Amazon S3 クライアントオブジェクトです。したがって、 を使用して作成されたクライアントを指定StaticReplayClientし、リクエストがネットワークを経由するのではなく、そのクライアントによって処理されるようにします。

    let size = determine_prefix_file_size(client, "test-bucket", "test-prefix") .await .unwrap(); assert_eq!(19, size); replay_client.assert_requests_match(&[]);

    の呼び出しdetermine_prefix_file_size()が完了すると、アサートを使用して、返された値が想定値と一致することを確認します。次に、 StaticReplayClientメソッドassert_requests_match()関数が呼び出されます。この関数は、記録された HTTP リクエストをスキャンし、再生クライアントの作成時に提供されたReplayEventオブジェクトの配列で指定されたリクエストとすべて一致することを確認します。

これらの例の完全なコードは、GitHub で確認できます。 GitHub

このページの内容

プライバシーサイト規約Cookie の設定
© 2025, Amazon Web Services, Inc. or its affiliates.All rights reserved.