Écrire des tests à l'aide d'un client fictif

Découvrez comment créer des stubs d'implémentations de clients réels pour injecter un mock pour les tests unitaires. L'utilisation d'un client mock avec les bibliothèques clientes Google Cloud pour Rust vous permet d'écrire des tests unitaires contrôlés et fiables qui n'effectuent pas d'appels réseau ni n'entraînent de frais de facturation.

Dépendances

Plusieurs frameworks de simulation sont disponibles pour Rust. Ce guide utilise mockall. Ajoutez-le en tant que dépendance de développement :

cargo add --dev mockall

De plus, ce guide utilise le client Speech pour faciliter la compréhension des exemples (mais ces concepts s'appliquent à tous les clients).

Ajoutez les dépendances requises à votre fichier Cargo.toml :

cargo add google-cloud-speech-v2 google-cloud-lro

Simuler un client

Pour tester votre code avec un client fictif, vous définissez une structure fictive, configurez son comportement attendu pour votre scénario de test, puis injectez cette structure fictive dans la logique de votre application. L'exemple suivant illustre ce workflow.

Commencez par ajouter des instructions use pour simplifier le code :

use google_cloud_gax as gax;
use google_cloud_speech_v2 as speech;

Supposons que l'application dispose d'une fonction qui utilise le client Speech pour appeler GetRecognizer, en définissant le champ name de la requête et en traitant la réponse du serveur.

// An example application function.
//
// It makes an RPC, setting some field. In this case, it is the `GetRecognizer`
// RPC, setting the name field.
//
// It processes the response from the server. In this case, it extracts the
// display name of the recognizer.
async fn my_application_function(client: &speech::client::Speech) -> gax::Result<String> {
    client
        .get_recognizer()
        .set_name("invalid-test-recognizer")
        .send()
        .await
        .map(|r| r.display_name)
}

Vous pouvez tester la façon dont l'application gère les différentes réponses du service.

Ensuite, définissez la structure fictive. Ce struct implémente le trait speech::stub::Speech.

mockall::mock! {
    #[derive(Debug)]
    Speech {}
    impl speech::stub::Speech for Speech {
        async fn get_recognizer(&self, req: speech::model::GetRecognizerRequest, _options: gax::options::RequestOptions) -> gax::Result<gax::response::Response<speech::model::Recognizer>>;
    }
}

Créez une instance du mock. Notez que la macro mockall::mock! ajoute un préfixe Mock au nom de la structure précédemment définie.

let mut mock = MockSpeech::new();

Définissez les attentes concernant la simulation. Par exemple, attendez-vous à ce que le code appelle GetRecognizer avec un nom spécifique et simule une réponse réussie du service.

mock.expect_get_recognizer()
    .withf(move |r, _|
        // Optionally, verify fields in the request.
        r.name == "invalid-test-recognizer")
    .return_once(|_, _| {
        Ok(gax::response::Response::from(
            speech::model::Recognizer::new().set_display_name("test-display-name"),
        ))
    });

Créez un client Speech à l'aide du mock :

let client = speech::client::Speech::from_stub(mock);

Appelez la fonction :

let display_name = my_application_function(&client).await?;

Vérifiez les résultats :

assert_eq!(display_name, "test-display-name");

Simuler des erreurs

La simulation d'erreurs est semblable à la simulation de réussites. Pour simuler une erreur, modifiez le résultat renvoyé par la simulation.

mock.expect_get_recognizer().return_once(|_, _| {
    // This time, return an error.
    use gax::error::Error;
    use gax::error::rpc::{Code, Status};
    let status = Status::default()
        .set_code(Code::NotFound)
        .set_message("Resource not found");
    Err(Error::service(status))
});

Un client créé avec from_stub() ne dispose pas de boucle de réessai interne. Il renvoie toutes les erreurs du stub directement à l'application.

Étapes suivantes

Pour afficher le code complet de ce guide, consultez le fichier source dans le dépôt google-cloud-rust sur GitHub.