쿠키 기본 설정 선택

당사는 사이트와 서비스를 제공하는 데 필요한 필수 쿠키 및 유사한 도구를 사용합니다. 고객이 사이트를 어떻게 사용하는지 파악하고 개선할 수 있도록 성능 쿠키를 사용해 익명의 통계를 수집합니다. 필수 쿠키는 비활성화할 수 없지만 '사용자 지정' 또는 ‘거부’를 클릭하여 성능 쿠키를 거부할 수 있습니다.

사용자가 동의하는 경우 AWS와 승인된 제3자도 쿠키를 사용하여 유용한 사이트 기능을 제공하고, 사용자의 기본 설정을 기억하고, 관련 광고를 비롯한 관련 콘텐츠를 표시합니다. 필수가 아닌 모든 쿠키를 수락하거나 거부하려면 ‘수락’ 또는 ‘거부’를 클릭하세요. 더 자세한 내용을 선택하려면 ‘사용자 정의’를 클릭하세요.

유닛 테스트

포커스 모드
유닛 테스트 - AWS SDK for Rust

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

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

AWS SDK for Rust 프로젝트에서 단위 테스트를 구현할 수 있는 방법은 여러 가지가 있지만 몇 가지 권장 사항은 다음과 같습니다.

  • mockall 크레이트automock에서를 사용하여 테스트를 생성하고 실행합니다.

  • AWS Smithy 런타임을 사용하여 일반적으로에서 사용되는 표준 HTTP 클라이언트 대신 사용할 수 있는 가짜 HTTP 클라이언트를 StaticReplayClient 생성합니다 AWS 서비스. 이 클라이언트는 네트워크를 통해 서비스와 통신하는 대신 지정한 HTTP 응답을 반환하므로 테스트는 테스트 목적으로 알려진 데이터를 가져옵니다.

Mockall을 사용하여 모의 자동 생성

mockall 크레이트automock에서 널리 사용되는를 사용하여 테스트에 필요한 모의 구현의 대부분을 자동으로 생성할 수 있습니다.

이 예제에서는 라는 사용자 지정 메서드를 테스트합니다determine_prefix_file_size(). 이 메서드는 Amazon S3를 호출하는 사용자 지정 list_objects() 래퍼 메서드를 호출합니다. 를 모의하여 Amazon S3에 실제로 연락하지 않고도 determine_prefix_file_size() 메서드list_objects()를 테스트할 수 있습니다.

  1. 프로젝트 디렉터리에 대한 명령 프롬프트에서 mockall crate를 종속 항목으로 추가합니다.

    $ 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 래퍼 구조 구현 중 사용할 두 가지를 결정하는 코드를 추가합니다.

    • 네트워크를 통해 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 유형이 사용되지 않는 경우 문제를 보고하지 않도록 리터에 지시합니다.

    • 조건은 테스트가 활성화되면 automock 속성을 설정해야 함을 #[cfg_attr(test, automock)] 나타냅니다. 이렇게 하면 이름이 인 모의 S3Impl를 생성mockall하도록 지시합니다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) }

유형은 HTTP 요청을 할 MockS3ImplS3Impl 및를 모두 지원하기 위해 래핑된 SDK for Rust 함수를 호출하는 데 S3 사용됩니다. 에서 자동으로 생성된 모의는 테스트가 활성화될 때 테스트 실패를 mockall 보고합니다.

GitHub에서 이러한 예제의 전체 코드를 볼 수 있습니다.

정적 재생을 사용하여 HTTP 트래픽 시뮬레이션

aws-smithy-runtime 크레이트에는 라는 테스트 유틸리티 클래스가 포함되어 있습니다StaticReplayClient. AWS 서비스 객체를 생성할 때 기본 HTTP 클라이언트 대신이 HTTP 클라이언트 클래스를 지정할 수 있습니다.

를 초기화StaticReplayClient할 때 HTTP 요청 및 응답 페어 목록을 ReplayEvent 객체로 제공합니다. 테스트가 실행되는 동안 각 HTTP 요청이 기록되고 클라이언트는 ReplayEvent 이벤트 목록의 다음에 있는 다음 HTTP 응답을 HTTP 클라이언트의 응답으로 반환합니다. 이렇게 하면 네트워크 연결 없이 알려진 데이터를 사용하여 테스트를 실행할 수 있습니다.

정적 재생 사용

정적 재생을 사용하려면 래퍼를 사용할 필요가 없습니다. 대신 테스트에서 사용할 데이터에 대해 실제 네트워크 트래픽이 어떤 모습이어야 하는지 결정하고 SDK가 AWS 서비스 클라이언트로부터 요청을 발행할 때마다 사용할 StaticReplayClient 수 있도록 해당 트래픽 데이터를에 제공합니다.

참고

AWS CLI 및 많은 네트워크 트래픽 분석기와 패킷 스니퍼 도구를 포함하여 예상 네트워크 트래픽을 수집하는 방법에는 여러 가지가 있습니다.

  • 예상 HTTP 요청과 반환해야 하는 응답을 지정하는 ReplayEvent 객체 목록을 생성합니다.

  • 이전 단계에서 생성된 HTTP 트랜잭션 목록을 StaticReplayClient 사용하여를 생성합니다.

  • 를 객체의 StaticReplayClient로 지정하여 AWS 클라이언트에 대한 구성 Config 객체를 생성합니다http_client.

  • 이전 단계에서 생성한 구성을 사용하여 AWS 서비스 클라이언트 객체를 생성합니다.

  • 를 사용하도록 구성된 서비스 객체를 사용하여 테스트하려는 작업을 수행합니다StaticReplayClient. SDK가 API 요청을 보낼 때마다 목록의 AWS다음 응답이 사용됩니다.

    참고

    전송된 요청이 ReplayEvent 객체 벡터의 응답과 일치하지 않더라도 목록의 다음 응답은 항상 반환됩니다.

  • 원하는 모든 요청이 이루어지면 StaticReplayClient.assert_requests_match() 함수를 호출하여 SDK에서 보낸 요청이 ReplayEvent 객체 목록의 요청과 일치하는지 확인합니다.

예제

이전 예제에서 동일한 determine_prefix_file_size() 함수에 대한 테스트를 살펴보되, 모의 대신 정적 재생을 사용하겠습니다.

  1. 프로젝트 디렉터리에 대한 명령 프롬프트에서 aws-smithy-runtime crate를 종속 항목으로 추가합니다.

    $ 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 요청 객체와가 일반적으로 회신할 정보를 나타내는 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. 이는 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에서 이러한 예제의 전체 코드를 볼 수 있습니다.

이 페이지에서

프라이버시사이트 이용 약관쿠키 기본 설정
© 2025, Amazon Web Services, Inc. 또는 계열사. All rights reserved.