Tests en Rust : Unit, Intégration, E2E au niveau avancé

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Tests avancés en Rust : des tests unitaires aux tests E2E

\n

Les tests sont une partie essentielle du développement de logiciels système fiables en Rust. Si les concepts de base (écrire simplement des tests avec #[test]) sont familiers à tous, les techniques avancées — travail avec des mocks, paramétrisation, attributs personnalisés et organisation des tests E2E — nécessitent une analyse distincte. Dans cet article, nous verrons comment amener les tests en Rust à un niveau professionnel, en utilisant les approches unit, integration et end-to-end.

\n\n

1. Tests unitaires : mock, paramétrisation et attributs personnalisés

\n

Les tests unitaires en Rust sont généralement écrits dans le même fichier que le code, dans le module tests. Cependant, au niveau avancé, il devient nécessaire d'isoler le code testé des dépendances externes.

\n\n

Objets mock avec des traits

\n

Pour créer des mocks en Rust, on utilise le plus souvent des traits. Vous définissez un trait, vous l'implémentez pour l'objet réel et pour le mock de test. Crates populaires : mockall et mockito (pour HTTP).

\n
use mockall::automock;\n\n#[automock]\ntrait Database {\n    fn get_user(&self, id: u32) -> String;\n}\n\nfn process_user(db: &dyn Database, id: u32) -> String {\n    let user = db.get_user(id);\n    format!("User: {}", user)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_process_user() {\n        let mut mock = MockDatabase::new();\n        mock.expect_get_user()\n            .with(predicate::eq(42))\n            .returning(|_| "Alice".to_string());\n        assert_eq!(process_user(&mock, 42), "User: Alice");\n    }\n}
\n\n

Tests paramétrés

\n

Répéter le même test avec différentes données d'entrée est une tâche courante. Le crate rstest fournit une solution élégante.

\n
use rstest::rstest;\n\n#[rstest]\n#[case(2, 3, 5)]\n#[case(0, 0, 0)]\n#[case(-1, 1, 0)]\nfn test_add(#[case] a: i32, #[case] b: i32, #[case] expected: i32) {\n    assert_eq!(a + b, expected);\n}
\n\n

Attributs de test personnalisés

\n

Parfois, une logique avant ou après le test est nécessaire. Vous pouvez créer vos propres attributs via des macros procédurales, mais il est plus simple d'utiliser le crate test-case ou ctor pour l'initialisation.

\n
// Exemple avec ctor pour initialiser un logger\n#[cfg(test)]\nmod tests {\n    use ctor::ctor;\n\n    #[ctor]\n    fn init() {\n        // Initialisation une fois avant tous les tests\n    }\n}
\n\n

2. Tests d'intégration : organisation et travail avec les dépendances externes

\n

Les tests d'intégration en Rust se trouvent dans le dossier tests/ à la racine du projet. Chaque fichier y est un crate séparé. Les techniques avancées incluent des modules communs et des tests avec de vraies bases de données ou API.

\n\n

Utilitaires communs pour les tests d'intégration

\n

Pour éviter de dupliquer le code (par exemple, la configuration d'un serveur de test), créez un module common dans tests/.

\n
// tests/common/mod.rs\npub fn setup_test_db() -> String {\n    // Configuration de la base de données de test\n    "connected".to_string()\n}\n\n// tests/integration_test.rs\nmod common;\n\n#[test]\nfn test_db_connection() {\n    let db = common::setup_test_db();\n    assert_eq!(db, "connected");\n}
\n\n

Travail avec les requêtes HTTP

\n

Pour tester les clients HTTP, utilisez mockito — il lance un serveur mock local.

\n
use mockito::{mock, server_url};\n\n#[tokio::test]\nasync fn test_api_call() {\n    let _m = mock("GET", "/users/1")\n        .with_status(200)\n        .with_body(r#"{"id":1,"name":"Alice"}"#)\n        .create();\n\n    let client = reqwest::Client::new();\n    let resp = client.get(&format!("{}/users/1", server_url()))\n        .send()\n        .await\n        .unwrap();\n    assert!(resp.status().is_success());\n}
\n\n

3. Tests E2E : cycle complet de l'application

\n

Les tests end-to-end vérifient le fonctionnement de l'ensemble du système : du lance

Blogs

Book Recommendations