

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# Secara otomatis menghasilkan tiruan menggunakan `mockall` AWS SDK untuk Rust
<a name="testing-automock"></a>

 AWS SDK for Rust Ini menyediakan beberapa pendekatan untuk menguji kode Anda yang berinteraksi dengannya Layanan AWS. Anda dapat secara otomatis menghasilkan sebagian besar implementasi tiruan yang dibutuhkan pengujian Anda dengan menggunakan yang populer `[automock](https://docs.rs/mockall/latest/mockall/attr.automock.html)` dari peti`[mockall](https://docs.rs/mockall/latest/mockall)`.

Contoh ini menguji metode kustom yang disebut`determine_prefix_file_size()`. Metode ini memanggil metode `list_objects()` pembungkus khusus yang memanggil Amazon S3. Dengan mengejek`list_objects()`, `determine_prefix_file_size()` metode ini dapat diuji tanpa benar-benar menghubungi Amazon S3. 

1. Dalam prompt perintah untuk direktori proyek Anda, tambahkan `[mockall](https://docs.rs/mockall/latest/mockall)` peti sebagai dependensi:

   ```
   $ cargo add --dev mockall
   ```

   Menggunakan `--dev` [opsi](https://doc.rust-lang.org/cargo/commands/cargo-add.html) menambahkan peti ke `[dev-dependencies]` bagian `Cargo.toml` file Anda. Sebagai [dependensi pengembangan](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#development-dependencies), itu tidak dikompilasi dan dimasukkan ke dalam biner akhir Anda yang digunakan untuk kode produksi.

   Kode contoh ini juga menggunakan Amazon Simple Storage Service sebagai contoh Layanan AWS.

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

   Ini menambahkan peti ke `[dependencies]` bagian `Cargo.toml` file Anda.

1. Sertakan `automock` modul dari `mockall` peti. 

   Sertakan juga perpustakaan lain yang terkait dengan Layanan AWS yang Anda uji, dalam hal ini, Amazon S3.

   ```
   use aws_sdk_s3 as s3;
   #[allow(unused_imports)]
   use mockall::automock;
   
   use s3::operation::list_objects_v2::{ListObjectsV2Error, ListObjectsV2Output};
   ```

1. Selanjutnya, tambahkan kode yang menentukan mana dari dua implementasi struktur pembungkus Amazon S3 aplikasi yang akan digunakan. 
   + Yang asli ditulis untuk mengakses Amazon S3 melalui jaringan.
   + Implementasi tiruan yang dihasilkan oleh`mockall`.

   Dalam contoh ini, salah satu yang dipilih diberi nama`S3`. Seleksi bersyarat berdasarkan `test` atribut:

   ```
   #[cfg(test)]
   pub use MockS3Impl as S3;
   #[cfg(not(test))]
   pub use S3Impl as S3;
   ```

1. `S3Impl`Struct adalah implementasi struktur pembungkus Amazon S3 yang benar-benar mengirimkan permintaan ke. AWS
   + Saat pengujian diaktifkan, kode ini tidak digunakan karena permintaan dikirim ke tiruan dan bukan AWS. `dead_code`Atribut memberitahu linter untuk tidak melaporkan masalah jika `S3Impl` tipe tidak digunakan.
   +  Kondisional `#[cfg_attr(test, automock)]` menunjukkan bahwa ketika pengujian diaktifkan, `automock` atribut harus diatur. Ini memberitahu `mockall` untuk menghasilkan tiruan `S3Impl` yang akan diberi nama`Mock{{S3Impl}}`.
   + Dalam contoh ini, `list_objects()` metodenya adalah panggilan yang ingin Anda ejek. `automock`akan secara otomatis membuat `expect_{{list_objects()}}` metode untuk Anda. 

   ```
   #[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
       }
   }
   ```

1. Buat fungsi pengujian dalam modul bernama`test`.
   + Kondisional `#[cfg(test)]` menunjukkan bahwa `mockall` harus membangun modul pengujian jika `test` atributnya. `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);
       }
   }
   ```
   + Setiap tes menggunakan `let mut mock = MockS3Impl::default();` untuk membuat `mock` instance dari`MockS3Impl`. 
   + Ini menggunakan `expect_list_objects()` metode tiruan (yang dibuat secara otomatis oleh`automock`) untuk mengatur hasil yang diharapkan ketika `list_objects()` metode digunakan di tempat lain dalam kode.
   + Setelah harapan ditetapkan, ia menggunakan ini untuk menguji fungsi dengan menelepon`determine_prefix_file_size()`. Nilai yang dikembalikan diperiksa untuk mengonfirmasi bahwa itu benar, menggunakan pernyataan.

1. `determine_prefix_file_size()`Fungsi ini menggunakan pembungkus Amazon S3 untuk mendapatkan ukuran file awalan:

   ```
   #[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)
   }
   ```

Jenis `S3` ini digunakan untuk memanggil SDK yang dibungkus untuk fungsi Rust untuk mendukung keduanya `S3Impl` dan `MockS3Impl` saat membuat permintaan HTTP. Mock yang dihasilkan secara otomatis oleh `mockall` melaporkan kegagalan pengujian apa pun saat pengujian diaktifkan.

Anda dapat [melihat kode lengkap untuk contoh-contoh ini](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rustv1/examples/testing) di GitHub.