

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Générez automatiquement des maquettes `mockall` à l'aide du AWS SDK pour Rust
<a name="testing-automock"></a>

 AWS SDK pour Rust Il fournit plusieurs approches pour tester votre code qui interagit avec Services AWS. Vous pouvez générer automatiquement la majorité des implémentations fictives dont vos tests ont besoin en utilisant la solution populaire « `[automock](https://docs.rs/mockall/latest/mockall/attr.automock.html)` from the `[mockall](https://docs.rs/mockall/latest/mockall)` crate ».

Cet exemple teste une méthode personnalisée appelée`determine_prefix_file_size()`. Cette méthode appelle une méthode `list_objects()` wrapper personnalisée qui appelle Amazon S3. En se moquant`list_objects()`, la `determine_prefix_file_size()` méthode peut être testée sans contacter Amazon S3. 

1. Dans une invite de commande pour le répertoire de votre projet, ajoutez le `[mockall](https://docs.rs/mockall/latest/mockall)` crate en tant que dépendance :

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

   L'utilisation de `--dev` [cette option](https://doc.rust-lang.org/cargo/commands/cargo-add.html) ajoute la caisse à la `[dev-dependencies]` section de votre `Cargo.toml` fichier. En tant que [dépendance de développement](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#development-dependencies), elle n'est pas compilée et incluse dans votre binaire final utilisé pour le code de production.

   Cet exemple de code utilise également Amazon Simple Storage Service comme exemple Service AWS.

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

   Cela ajoute la caisse à la `[dependencies]` section de votre `Cargo.toml` fichier.

1. Incluez le `automock` module de la `mockall` caisse. 

   Incluez également toute autre bibliothèque liée à celle Service AWS que vous testez, dans ce cas, Amazon S3.

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

1. Ajoutez ensuite du code qui détermine laquelle des deux implémentations de la structure d'enveloppe Amazon S3 de l'application doit être utilisée. 
   + Le vrai écrit pour accéder à Amazon S3 via le réseau.
   + L'implémentation fictive générée par`mockall`.

   Dans cet exemple, le nom est attribué à celui qui est sélectionné`S3`. La sélection est conditionnelle en fonction de l'`test`attribut :

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

1. La `S3Impl` structure est l'implémentation de la structure d'emballage Amazon S3 qui envoie réellement des demandes à. AWS
   + Lorsque le test est activé, ce code n'est pas utilisé car la demande est envoyée au simulateur et non AWS. L'`dead_code`attribut indique au linter de ne pas signaler de problème si le `S3Impl` type n'est pas utilisé.
   +  Le conditionnel `#[cfg_attr(test, automock)]` indique que lorsque le test est activé, l'`automock`attribut doit être défini. Cela indique `mockall` de générer une maquette `S3Impl` qui sera nommée`Mock{{S3Impl}}`.
   + Dans cet exemple, la `list_objects()` méthode est l'appel que vous souhaitez simuler. `automock`créera automatiquement une `expect_{{list_objects()}}` méthode pour vous. 

   ```
   #[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. Créez les fonctions de test dans un module nommé`test`.
   + Le conditionnel `#[cfg(test)]` indique qui `mockall` doit créer le module de test si l'`test`attribut est`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);
       }
   }
   ```
   + Chaque test permet `let mut mock = MockS3Impl::default();` de créer une `mock` instance de`MockS3Impl`. 
   + Il utilise la `expect_list_objects()` méthode de la maquette (qui a été créée automatiquement par`automock`) pour définir le résultat attendu lorsque la `list_objects()` méthode est utilisée ailleurs dans le code.
   + Une fois les attentes établies, il les utilise pour tester la fonction en appelant`determine_prefix_file_size()`. La valeur renvoyée est vérifiée pour confirmer qu'elle est correcte, à l'aide d'une assertion.

1. La `determine_prefix_file_size()` fonction utilise le wrapper Amazon S3 pour obtenir la taille du fichier de préfixe :

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

Le type `S3` est utilisé pour appeler le SDK encapsulé pour les fonctions Rust afin de prendre en charge les deux `S3Impl` et `MockS3Impl` lors de l'envoi de requêtes HTTP. La maquette générée automatiquement par `mockall` signale tout échec de test lorsque le test est activé.

Vous pouvez [consulter le code complet de ces exemples](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rustv1/examples/testing) sur GitHub.