mockall pour Rust : guide complet avec exemples
1. Qu'est-ce que mockall et pourquoi l'utiliser ?
La bibliothèque mockall est un framework puissant pour créer automatiquement des objets mock (mock objects) en Rust. Conçue pour les tests unitaires, elle permet aux développeurs d'isoler facilement le code testé des dépendances externes comme les bases de données, les clients HTTP, les systèmes de fichiers ou tout autre service. Contrairement à l'écriture manuelle de stubs de test, mockall génère automatiquement des structures mock à partir des traits existants, offrant une API flexible pour configurer des attentes (expectations) et vérifier les appels.
Pourquoi en avez-vous besoin ? Dans les projets réels, le code n'existe que rarement dans un vide. Les fonctions appellent d'autres fonctions, les modules dépendent de bibliothèques externes. Lors des tests d'un module spécifique, vous ne voulez pas que votre test dépende du bon fonctionnement de la base de données ou du réseau. Mockall résout ce problème en créant des mocks qui imitent le comportement des dépendances réelles. Vous pouvez définir ce qu'une méthode doit retourner pour des arguments donnés, combien de fois elle doit être appelée, et même vérifier l'ordre des appels. Cela rend les tests rapides, fiables et reproductibles.
La caractéristique clé de mockall est son intégration avec le système de types de Rust et son fonctionnement à la compilation via l'attribut #[automock]. Cela signifie que les mocks sont générés automatiquement pour n'importe quel trait, ce qui fait gagner un temps considérable et réduit le code boilerplate. La bibliothèque prend en charge les fonctions asynchrones, les génériques, les traits avec types associés et bien plus encore, ce qui en fait un outil indispensable pour le développement sérieux en Rust.
2. Installation
Pour utiliser mockall dans votre projet Rust, ajoutez la dépendance dans le fichier Cargo.toml. La bibliothèque s'installe via le gestionnaire de paquets standard Cargo. Il est recommandé de l'ajouter uniquement en tant que dev-dependency, car elle est utilisée exclusivement pour les tests.
# Cargo.toml
[dev-dependencies]
mockall = "0.13" # Utilisez la version actuelle au moment de la lecture
Après avoir ajouté cette ligne, exécutez la commande cargo build ou cargo test pour que Cargo télécharge et compile la bibliothèque. Si vous travaillez sur un projet avec d'autres dépendances, assurez-vous que la version de mockall est compatible avec votre version de Rust (généralement Rust 1.70+). Pour vérifier la version la plus récente, consultez crates.io/crates/mockall.
3. Démarrage rapide
Créons un exemple minimal fonctionnel. Supposons que nous ayons un trait Greeter que nous souhaitons mocker dans un test. Avec #[automock], nous obtenons automatiquement une structure MockGreeter.
// src/lib.rs
use mockall::automock;
#[automock]
pub trait Greeter {
fn greet(&self, name: &str) -> String;
}
pub fn run_greeter(greeter: &impl Greeter, name: &str) -> String {
greeter.greet(name)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_greeting() {
// Création du mock
let mut mock = MockGreeter::new();
// Configuration de l'attente : lors de l'appel greet("Alice"), retourner "Hello, Alice!"
mock.expect_greet()
.with(predicate::eq("Alice"))
.returning(|name| format!("Hello, {}!", name));
// Appel de la fonction testée
let result = run_greeter(&mock, "Alice");
// Vérification du résultat
assert_eq!(result, "Hello, Alice!");
}
}
Lancez le test avec la commande cargo test. Si tout est correctement configuré, le test passera avec succès.