

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Gere simulações automaticamente usando o `mockall` AWS SDK para Rust
<a name="testing-automock"></a>

O AWS SDK para Rust fornece várias abordagens para testar seu código que interage com Serviços da AWS. Você pode gerar automaticamente a maioria das implementações de simulação de que seus testes precisam usando a popular `[automock](https://docs.rs/mockall/latest/mockall/attr.automock.html)` da caixa `[mockall](https://docs.rs/mockall/latest/mockall)`.

Este exemplo testa um método personalizado chamado `determine_prefix_file_size()`. Esse método chama um método de wrapper `list_objects()` personalizado que chama o Amazon S3. Ao simular `list_objects()`, o método `determine_prefix_file_size()` pode ser testado sem realmente entrar em contato com o Amazon S3. 

1. Em um prompt de comando para o diretório do seu projeto, adicione a caixa `[mockall](https://docs.rs/mockall/latest/mockall)` como uma dependência:

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

   Usar a [opção](https://doc.rust-lang.org/cargo/commands/cargo-add.html) `--dev` adiciona a caixa à seção `[dev-dependencies]` do seu arquivo `Cargo.toml`. Como uma [dependência de desenvolvimento](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#development-dependencies), ela não é compilada e incluída no binário final usado para o código de produção.

   Esse código de exemplo também usa o Amazon Simple Storage Service como o AWS service (Serviço da AWS) de exemplo.

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

   Isso adiciona a caixa à seção `[dependencies]` do seu arquivo `Cargo.toml`.

1. Inclua o módulo `automock` da caixa `mockall`. 

   Inclua também quaisquer outras bibliotecas relacionadas à AWS service (Serviço da AWS) que você está testando, neste caso, o Amazon S3.

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

1. Em seguida, adicione o código que determina qual das duas implementações da estrutura de wrapper da aplicação do Amazon S3 usar. 
   + A verdadeiro foi gravada para acessar o Amazon S3 pela rede.
   + A implementação simulada gerada é por `mockall`.

   Neste exemplo, a que é selecionada recebe o nome de `S3`. A seleção é condicional com base no atributo `test`:

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

1. A `S3Impl` estrutura é a implementação da estrutura de wrapper do Amazon S3 que realmente envia solicitações para o. AWS
   + Quando os testes estão habilitados, esse código não é usado porque a solicitação é enviada para a simulação e não para a AWS. O atributo `dead_code` diz ao linter que não relate um problema se o tipo `S3Impl` não for usado.
   +  A condicional `#[cfg_attr(test, automock)]` indica que, quando os testes estão habilitados, o atributo `automock` deve ser definido. Isso faz com que `mockall` gere uma simulação de `S3Impl` que será nomeada `Mock{{S3Impl}}`.
   + Neste exemplo, o método `list_objects()` é a chamada que você deseja simular. `automock` criará automaticamente um método `expect_{{list_objects()}}` para você. 

   ```
   #[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. Crie as funções de teste em um módulo chamado `test`.
   + A condicional `#[cfg(test)]` indica que `mockall` deve construir o módulo de teste se o atributo `test` for `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);
       }
   }
   ```
   + Cada teste usa `let mut mock = MockS3Impl::default();` para criar uma instância `mock` de `MockS3Impl`. 
   + Ele usa o método `expect_list_objects()` da simulação (criada automaticamente por `automock`) para definir o resultado esperado para quando o método `list_objects()` for usado em outro lugar no código.
   + Após estabelecer as expectativas, ele as usa para testar a função chamando `determine_prefix_file_size()`. O valor retornado é verificado para confirmar se está correto, usando uma afirmação.

1. A função `determine_prefix_file_size()` usa o wrapper Amazon S3 para obter o tamanho do arquivo de prefixo:

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

O tipo `S3` é usado para chamar o SDK encapsulado para funções do Rust para oferecer suporte a ambos `S3Impl` e `MockS3Impl` ao fazer solicitações HTTP. A simulação gerada automaticamente pelo `mockall` relata qualquer falha de teste quando os testes são habilitados.

Você pode [ver o código completo desses exemplos](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rustv1/examples/testing) em GitHub.