

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 在适用于 Rust 的 AWS SDK 中使用静态重播模拟 HTTP 流量
<a name="testing-replay"></a>

 适用于 Rust 的 AWS SDK 提供了多种方法来测试与 AWS 服务之交互的代码。本主题介绍了如何使用 `StaticReplayClient` 创建虚假 HTTP 客户端，该客户端可以代替 AWS 服务通常使用的标准 HTTP 客户端。该客户端返回您指定的 HTTP 响应，而不是通过网络与服务通信，以便测试能够获得已知数据用于测试目的。

`aws-smithy-http-client` crate 包含一个名为 [https://docs.rs/aws-smithy-http-client/latest/aws_smithy_http_client/test_util/struct.StaticReplayClient.html](https://docs.rs/aws-smithy-http-client/latest/aws_smithy_http_client/test_util/struct.StaticReplayClient.html) 的测试实用程序类。创建 AWS 服务 对象时，可以指定此 HTTP 客户端类而不是默认的 HTTP 客户端。

初始化 `StaticReplayClient` 时，您可以提供 HTTP 请求和响应对的列表作为 `ReplayEvent` 对象。在测试运行时，系统会记录每个 HTTP 请求，客户端将在事件列表中下一个 `ReplayEvent` 中找到的下一个 HTTP 响应作为 HTTP 客户端的响应返回。这样，测试就可以在没有网络连接的情况下使用已知数据运行。

## 使用静态重播
<a name="testing-replay-steps"></a>

要使用静态重播，无需使用包装器。但是，您需要确定测试将使用的数据的实际网络流量应是什么样的，并将该流量数据提供给 `StaticReplayClient`，以便在每次 SDK 从 AWS 服务 客户端发出请求时使用。

**注意**  
有多种方法可以收集预期的网络流量，包括许多网络流量分析器和数据包嗅探器工具。 AWS CLI 
+ 创建 `ReplayEvent` 对象列表，指定预期的 HTTP 请求以及应针对这些请求返回的响应。
+ 使用上一步创建的 HTTP 事务列表创建 `StaticReplayClient`。
+ 为 AWS 客户端创建配置对象，将指定`StaticReplayClient`为该`Config`对象的`http_client`。
+ 使用在上一步中创建的配置创建 AWS 服务 客户端对象。
+ 使用配置为使用 `StaticReplayClient` 的服务对象，执行您要测试的操作。每当 SDK 向发送 API 请求时 AWS，都会使用列表中的下一个响应。
**注意**  
即使发送的请求与 `ReplayEvent` 对象向量中的请求不匹配，系统也总是会返回列表中的下一个响应。
+ 发出所有所需请求后，调用 `StaticReplayClient.assert_requests_match()` 函数以验证 SDK 发送的请求是否与 `ReplayEvent` 对象列表中的请求相匹配。

## 示例
<a name="testing-replay-example"></a>

我们来看上一个示例中同一 `determine_prefix_file_size()` 函数的测试，但这次使用的是静态重播而不是模拟。

1. 在项目目录的命令提示符中，将 [https://crates.io/crates/aws-smithy-http-client](https://crates.io/crates/aws-smithy-http-client) crate 添加为依赖项：

   ```
   $ cargo add --dev aws-smithy-http-client --features test-util
   ```

   使用 `--dev` [选项](https://doc.rust-lang.org/cargo/commands/cargo-add.html)可将 crate 添加到 `Cargo.toml` 文件的 `[dev-dependencies]` 部分。作为[开发依赖项](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#development-dependencies)，它不会被编译并包含在用于生产代码的最终二进制文件中。

   此示例代码还使用 Amazon Simple Storage Service 作为示例 AWS 服务。

   ```
   $ cargo add aws-sdk-s3
   ```

   这会将 crate 添加到 `Cargo.toml` 文件的 `[dependencies]` 部分。

1. 在测试代码模块中，包含您需要的两种类型。

   ```
   use aws_smithy_http_client::test_util::{ReplayEvent, StaticReplayClient};
   use aws_sdk_s3::primitives::SdkBody;
   ```

1. 测试首先创建表示测试期间应发生的每个 HTTP 事务的 `ReplayEvent` 结构。每个事件都包含一个 HTTP 请求对象和一个 HTTP 响应对象，表示 AWS 服务 通常会回复的信息。这些事件会传递到对 `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` 中。这表示一个 HTTP 客户端，适用于 Rust 的 SDK 可以通过在客户端配置中指定该客户端来使用它。

1. 要创建 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。

1. 通过调用需要测试的函数来运行测试。在此示例中，该函数名称为 `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` 对象数组中指定的请求相匹配。

您可以在[上查看这些示例的完整代码](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rustv1/examples/testing) GitHub。