

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# AWS SDK for Rust`aws-smithy-mocks`에서를 사용한 단위 테스트
<a name="testing-smithy-mocks"></a>

는와 상호 작용하는 코드를 테스트하기 위한 여러 접근 방식을 AWS SDK for Rust 제공합니다 AWS 서비스. 이 주제에서는 테스트 목적으로 AWS SDK 클라이언트 응답을 모의하는 간단하지만 강력한 방법을 제공하는 [https://docs.rs/aws-smithy-mocks/latest/aws_smithy_mocks/](https://docs.rs/aws-smithy-mocks/latest/aws_smithy_mocks/) 크레이트 사용 방법을 설명합니다.

## 개요
<a name="overview-smithy-mock"></a>

에서 사용하는 코드에 대한 테스트를 작성할 때 실제 네트워크 호출을 피하는 AWS 서비스것이 좋습니다. `aws-smithy-mocks` 크레이트는 다음을 수행할 수 있는 솔루션을 제공합니다.
+ SDK가 특정 요청에 응답하는 방법을 정의하는 모의 규칙을 생성합니다.
+ 다양한 유형의 응답(성공, 오류, HTTP 응답)을 반환합니다.
+ 속성을 기반으로 요청을 일치시킵니다.
+ 재시도 동작을 테스트하기 위한 응답 시퀀스를 정의합니다.
+ 규칙이 예상대로 사용되었는지 확인합니다.

## 종속성 추가
<a name="dependency-smithy-mock"></a>

프로젝트 디렉터리에 대한 명령 프롬프트에서 [https://crates.io/crates/aws-smithy-mocks](https://crates.io/crates/aws-smithy-mocks) 크레이트를 종속성으로 추가합니다.

```
$ cargo add --dev aws-smithy-mocks
```

`--dev` [옵션](https://doc.rust-lang.org/cargo/commands/cargo-add.html)을 사용하면 `Cargo.toml` 파일의 `[dev-dependencies]` 섹션에 크레이트가 추가됩니다. [개발 종속성](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#development-dependencies)으로서 컴파일되지 않으며 프로덕션 코드에 사용되는 최종 바이너리에 포함되지 않습니다.

이 예제 코드는 Amazon Simple Storage Service도 예제로 사용 AWS 서비스하며 기능가 필요합니다`test-util`.

```
$ cargo add aws-sdk-s3 --features test-util
```

이렇게 하면 `[dependencies]` 파일의 `Cargo.toml` 섹션에 크레이트가 추가됩니다.

## 기본 사용법
<a name="basic-smithy-mocks"></a>

 다음은 `aws-smithy-mocks`를 사용하여 Amazon Simple Storage Service(Amazon S3와 상호 작용하는 코드를 테스트하는 방법의 간단한 예입니다.

```
use aws_sdk_s3::operation::get_object::GetObjectOutput;
use aws_sdk_s3::primitives::ByteStream;
use aws_smithy_mocks::{mock, mock_client};

#[tokio::test]
async fn test_s3_get_object() {
    // Create a rule that returns a successful response
    let get_object_rule = mock!(aws_sdk_s3::Client::get_object)
        .then_output(|| {
            GetObjectOutput::builder()
                .body(ByteStream::from_static(b"test-content"))
                .build()
        });

    // Create a mocked client with the rule
    let s3 = mock_client!(aws_sdk_s3, [&get_object_rule]);

    // Use the client as you would normally
    let result = s3
        .get_object()
        .bucket("test-bucket")
        .key("test-key")
        .send()
        .await
        .expect("success response");

    // Verify the response
    let data = result.body.collect().await.expect("successful read").to_vec();
    assert_eq!(data, b"test-content");

    // Verify the rule was used
    assert_eq!(get_object_rule.num_calls(), 1);
}
```

## 모의 규칙 생성
<a name="creating-rules-smithy-mocks"></a>

규칙은 클라이언트 작업을 인수로 사용하는 `mock!` 매크로를 사용하여 생성됩니다. 그런 다음 규칙의 작동 방식을 구성할 수 있습니다.

### 일치하는 요청
<a name="matching-requests-smithy-mocks"></a>

 요청 속성에서 일치시켜 규칙을 보다 구체적으로 만들 수 있습니다.

```
let rule = mock!(Client::get_object)
    .match_requests(|req| req.bucket() == Some("test-bucket") && req.key() == Some("test-key"))
    .then_output(|| {
        GetObjectOutput::builder()
            .body(ByteStream::from_static(b"test-content"))
            .build()
    });
```

### 다양한 응답 유형
<a name="diff-response-smithy-mocks"></a>

다양한 유형의 응답을 반환할 수 있습니다.

```
// Return a successful response
let success_rule = mock!(Client::get_object)
    .then_output(|| GetObjectOutput::builder().build());

// Return an error
let error_rule = mock!(Client::get_object)
    .then_error(|| GetObjectError::NoSuchKey(NoSuchKey::builder().build()));

// Return a specific HTTP response
let http_rule = mock!(Client::get_object)
    .then_http_response(|| {
        HttpResponse::new(
            StatusCode::try_from(503).unwrap(),
            SdkBody::from("service unavailable")
        )
    });
```

## 재시도 동작 테스트
<a name="testing-retry-behavior-smithy-mocks"></a>

`aws-smithy-mocks`의 가장 강력한 기능 중 하나는 응답 시퀀스를 정의하여 재시도 동작을 테스트하는 기능입니다.

```
// Create a rule that returns 503 twice, then succeeds
let retry_rule = mock!(aws_sdk_s3::Client::get_object)
    .sequence()
    .http_status(503, None)                          // First call returns 503
    .http_status(503, None)                          // Second call returns 503
    .output(|| GetObjectOutput::builder().build())   // Third call succeeds
    .build();

// With repetition using times()
let retry_rule = mock!(Client::get_object)
    .sequence()
    .http_status(503, None)
    .times(2)                                        // First two calls return 503
    .output(|| GetObjectOutput::builder().build())   // Third call succeeds
    .build();
```

## 규칙 모드
<a name="rule-modes-smithy-mocks"></a>

규칙 모드를 사용하여 규칙을 일치시키고 적용하는 방법을 제어할 수 있습니다.

```
// Sequential mode: Rules are tried in order, and when a rule is exhausted, the next rule is used
let client = mock_client!(aws_sdk_s3, RuleMode::Sequential, [&rule1, &rule2]);

// MatchAny mode: The first matching rule is used, regardless of order
let client = mock_client!(aws_sdk_s3, RuleMode::MatchAny, [&rule1, &rule2]);
```

## 예: 재시도 동작 테스트
<a name="example-retry-smithy-mocks"></a>

다음은 재시도 동작을 테스트하는 방법을 보여주는 보다 완전한 예제입니다.

```
use aws_sdk_s3::operation::get_object::GetObjectOutput;
use aws_sdk_s3::config::RetryConfig;
use aws_sdk_s3::primitives::ByteStream;
use aws_smithy_mocks::{mock, mock_client, RuleMode};

#[tokio::test]
async fn test_retry_behavior() {
    // Create a rule that returns 503 twice, then succeeds
    let retry_rule = mock!(aws_sdk_s3::Client::get_object)
        .sequence()
        .http_status(503, None)
        .times(2)
        .output(|| GetObjectOutput::builder()
            .body(ByteStream::from_static(b"success"))
            .build())
        .build();

    // Create a mocked client with the rule and custom retry configuration
    let s3 = mock_client!(
        aws_sdk_s3,
        RuleMode::Sequential,
        [&retry_rule],
        |client_builder| {
            client_builder.retry_config(RetryConfig::standard().with_max_attempts(3))
        }
    );

    // This should succeed after two retries
    let result = s3
        .get_object()
        .bucket("test-bucket")
        .key("test-key")
        .send()
        .await
        .expect("success after retries");

    // Verify the response
    let data = result.body.collect().await.expect("successful read").to_vec();
    assert_eq!(data, b"success");

    // Verify all responses were used
    assert_eq!(retry_rule.num_calls(), 3);
}
```

## 예: 요청 파라미터에 따른 다양한 응답
<a name="example-request-param-smithy-mocks"></a>

요청 파라미터에 따라 다른 응답을 반환하는 규칙을 생성할 수도 있습니다.

```
use aws_sdk_s3::operation::get_object::{GetObjectOutput, GetObjectError};
use aws_sdk_s3::types::error::NoSuchKey;
use aws_sdk_s3::Client;
use aws_sdk_s3::primitives::ByteStream;
use aws_smithy_mocks::{mock, mock_client, RuleMode};

#[tokio::test]
async fn test_different_responses() {
    // Create rules for different request parameters
    let exists_rule = mock!(Client::get_object)
        .match_requests(|req| req.bucket() == Some("test-bucket") && req.key() == Some("exists"))
        .sequence()
        .output(|| GetObjectOutput::builder()
            .body(ByteStream::from_static(b"found"))
            .build())
        .build();

    let not_exists_rule = mock!(Client::get_object)
        .match_requests(|req| req.bucket() == Some("test-bucket") && req.key() == Some("not-exists"))
        .sequence()
        .error(|| GetObjectError::NoSuchKey(NoSuchKey::builder().build()))
        .build();

    // Create a mocked client with the rules in MatchAny mode
    let s3 = mock_client!(aws_sdk_s3, RuleMode::MatchAny, [&exists_rule, &not_exists_rule]);

    // Test the "exists" case
    let result1 = s3
        .get_object()
        .bucket("test-bucket")
        .key("exists")
        .send()
        .await
        .expect("object exists");

    let data = result1.body.collect().await.expect("successful read").to_vec();
    assert_eq!(data, b"found");

    // Test the "not-exists" case
    let result2 = s3
        .get_object()
        .bucket("test-bucket")
        .key("not-exists")
        .send()
        .await;

    assert!(result2.is_err());
    assert!(matches!(result2.unwrap_err().into_service_error(),
                    GetObjectError::NoSuchKey(_)));
}
```

## 모범 사례
<a name="best-practices-smithy-mocks"></a>

테스트에 `aws-smithy-mocks`를 사용하는 경우:

1.  특정 요청 일치: 규칙을 의도한 요청, 특히 `RuleMode:::MatchAny`에만 적용하려면 `match_requests()`를 사용합니다.

1.  규칙 사용량 확인: 규칙이 실제로 사용되었는지 `rule.num_calls()`를 확인합니다.

1.  테스트 오류 처리: 코드를 사용하여 오류를 처리하는 방법을 테스트하기 위해 오류를 반환하는 규칙을 생성합니다.

1.  재시도 로직 테스트: 응답 시퀀스를 사용하여 코드가 사용자 지정 재시도 분류자 또는 기타 재시도 동작을 올바르게 처리하는지 확인합니다.

1. 테스트 집중 유지: 한 번의 테스트로 모든 것을 다루기보다 다양한 시나리오에 대해 별도의 테스트를 생성합니다.