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
Kit 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
from the mockall
crate ».
Cet exemple teste une méthode personnalisée appeléedetermine_prefix_file_size()
. Cette méthode appelle une méthode list_objects()
wrapper personnalisée qui appelle Amazon S3. En se moquantlist_objects()
, la determine_prefix_file_size()
méthode peut être testée sans contacter Amazon S3.
-
Dans une invite de commande pour le répertoire de votre projet, ajoutez le
mockall
crate en tant que dépendance :$
cargo add --dev mockallL'utilisation de
--dev
cette optionajoute la caisse à la [dev-dependencies]
section de votreCargo.toml
fichier. En tant que dépendance de développement, 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-s3Cela ajoute la caisse à la
[dependencies]
section de votreCargo.toml
fichier. -
Incluez le
automock
module de lamockall
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};
-
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;
-
-
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 leS3Impl
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 indiquemockall
de générer une maquetteS3Impl
qui sera nomméeMock
.S3Impl
-
Dans cet exemple, la
list_objects()
méthode est l'appel que vous souhaitez simuler.automock
créera automatiquement uneexpect_
méthode pour vous.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 } }
-
-
Créez les fonctions de test dans un module nommé
test
.-
Le conditionnel
#[cfg(test)]
indique quimockall
doit créer le module de test si l'test
attribut esttrue
.
#[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 unemock
instance deMockS3Impl
. -
Il utilise la
expect_list_objects()
méthode de la maquette (qui a été créée automatiquement parautomock
) pour définir le résultat attendu lorsque lalist_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.
-
-
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