É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 à des fins de tests unitaires. L'utilisation d'un client mock avec les Google Cloud bibliothèques clientes 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 mocking 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

Créer un mock de client

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

Tout d'abord, ajoutez 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, définir le champ name de la requête et traiter 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 différentes réponses du service.

Ensuite, définissez la structure mock. Cette structure implémente le speech::stub::Speech trait.

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 mockall::mock! macro ajoute un Mock préfixe au nom de la structure précédemment définie.

let mut mock = MockSpeech::new();

Définissez les attentes concernant le mock. Par exemple, attendez-vous à ce que le code appelle GetRecognizer avec un nom spécifique et simule une réponse positive 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 le mock.

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 comporte pas de boucle de nouvelle tentative 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 google-cloud-rust dépôt sur GitHub.