Nouveau : Datasets open source gratuits disponibles !Decouvrir →
🧪
Intermediaire 25 min Rust

Tester Rust avec Cargo Test

Pourquoi Tester Rust avec Cargo Test ?

Tester votre code est essentiel en développement, mais il peut être particulièrement délicat pour les langages compilés comme Rust. Les erreurs de compilation peuvent être difficiles à repérer, et même si Rust compile votre code sans erreur, cela ne signifie pas qu'il fonctionne correctement à l'exécution.

Un cas d'usage concret : imaginez que vous êtes en train de développer une application web qui gère des requêtes HTTP. Si vous n'avez pas de tests en place, il est facile de commettre des erreurs dans votre logique de traitement des requêtes, ce qui peut entraîner des comportements imprévisibles ou des vulnérabilités de sécurité.

Prerequis

  • Connaissance de base de Rust et du langage
  • Rust installé sur votre système (https://www.rust-lang.org/tools/install)
  • Cargo (le package manager et le build system de Rust) est généralement inclus avec l'installation de Rust

Concepts fondamentaux

Le Testeur

Cargo, le package manager de Rust, comprend un outil appelé cargo test qui permet d'exécuter les tests dans votre projet. Un test en Rust est simplement une fonction qui vérifie si une certaine condition est vraie.

Exemple

// src/lib.rs
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}

Dans cet exemple, la fonction it_works vérifie si l'expression 2 + 2 == 4 est vraie. Si elle ne l'est pas, le test échouera.

Le Hook

Les hooks sont des fonctions qui sont exécutées avant et après chaque test. Ils peuvent être utilisés pour initialiser ou détruire des ressources communes à plusieurs tests.

Exemple

// src/lib.rs
#[cfg(test)]
mod tests {
    use std::fs;

    #[setup]
    fn setup() {
        fs::write("temp.txt", "Hello, world!").unwrap();
    }

    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }

    #[teardown]
    fn teardown() {
        fs::remove_file("temp.txt").unwrap();
    }
}

Dans cet exemple, la fonction setup est exécutée avant chaque test et crée un fichier temporaire. La fonction teardown est ensuite exécutée après chaque test pour supprimer le fichier.

Mise en pratique : projet fil rouge

Nous allons créer un petit gestionnaire de tâches en Rust avec des tests. Ce gestionnaire permettra d'ajouter, de lister et de marquer comme terminées les tâches.

Étape 1 : Création du Projet

cargo new task_manager
cd task_manager

Étape 2 : Création de la Structure des Fichiers

Créez un fichier task_manager.rs dans le dossier src.

// src/task_manager.rs
use std::collections::HashMap;

pub struct TaskManager {
    tasks: HashMap<String, bool>,
}

impl TaskManager {
    pub fn new() -> Self {
        TaskManager {
            tasks: HashMap::new(),
        }
    }

    pub fn add_task(&mut self, task_name: String) {
        self.tasks.insert(task_name, false);
    }

    pub fn list_tasks(&self) -> Vec<String> {
        let mut tasks = Vec::new();
        for (task, completed) in &self.tasks {
            if *completed {
                tasks.push(format!("{} [COMPLETED]", task));
            } else {
                tasks.push(format!("{}", task));
            }
        }
        tasks
    }

    pub fn mark_task_completed(&mut self, task_name: String) {
        if let Some(task) = self.tasks.get_mut(&task_name) {
            *task = true;
        }
    }
}

Étape 3 : Création des Tests

Créez un fichier tests.rs dans le dossier src.

// src/tests.rs
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_add_task() {
        let mut task_manager = TaskManager::new();
        task_manager.add_task("Task 1".to_string());
        assert_eq!(task_manager.list_tasks(), vec!["Task 1"]);
    }

    #[test]
    fn test_mark_task_completed() {
        let mut task_manager = TaskManager::new();
        task_manager.add_task("Task 1".to_string());
        task_manager.mark_task_completed("Task 1".to_string());
        assert_eq!(task_manager.list_tasks(), vec!["Task 1 [COMPLETED]"]);
    }
}

Étape 4 : Exécution des Tests

cargo test

Erreurs frequentes et debugging

Erreur 1: cannot find type 'HashMap' in this scope

Cause: Vous n'avez pas importé le type HashMap.

Correction:

// src/lib.rs
use std::collections::HashMap;

Erreur 2: expected struct, found tuple

Cause: Vous avez utilisé une syntaxe incorrecte pour accéder à un élément du HashMap.

Correction:

// src/task_manager.rs
if let Some(task) = self.tasks.get_mut(&task_name) {
    *task = true;
}

Erreur 3: missing lifetime specifier

Cause: Vous n'avez pas spécifié une durée de vie pour les références dans votre structure.

Correction:

// src/task_manager.rs
pub struct TaskManager<'a> {
    tasks: HashMap<&'a str, bool>,
}

Pour aller plus loin

  1. Tests Asynchrones: Si vous travaillez avec des opérations asynchrones, Rust offre un support intégré pour les tests asynchrones via #[tokio::test] (https://docs.rs/tokio/latest/tokio/test/index.html).
  2. Mocking: Utilisez des bibliothèques comme mockall pour créer des doubles de fonction pour tester votre code en isolation (https://crates.io/crates/mockall).
  3. Performance Tests: Rust permet également d'écrire des tests de performance pour mesurer l'efficacité de votre code.

Défi Pratique

Développez un petit outil CLI qui utilise le gestionnaire de tâches que vous venez de créer. L'outil devrait permettre à l'utilisateur d'ajouter, de lister et de marquer comme terminées des tâches via la ligne de commande.

Indice: Vous pouvez utiliser la bibliothèque clap pour gérer les arguments de ligne de commande (https://crates.io/crates/clap).

Besoin d'aide sur Rust ?

Besoin d'aide sur un projet technique ? Decrivez-le pour des conseils personnalises.

Recevoir des conseils

Questions frequentes

Qu'est-ce que Cargo Test dans Rust ?
Cargo Test est un outil intégré qui permet de créer, exécuter et gérer les tests unitaires et d'intégration pour votre projet Rust.
Comment ajouter une fonction test à mon projet Rust ?
Pour ajouter une fonction test à votre projet Rust, utilisez le mot-clé `#[test]` avant la définition de la fonction. Par exemple : `#[test] fn mon_test() { assert!(1 + 1 == 2); }`.
Comment exécuter les tests dans mon projet Rust ?
Pour exécuter les tests dans votre projet Rust, utilisez la commande `cargo test` dans votre terminal. Cargo va alors compiler et exécuter tous les tests définis dans votre projet.

Pages liees

Chaque semaine, le meilleur de la tech francaise

Tendances, salaires, outils et opportunites — directement dans votre boite mail.

Gratuit. Desabonnement en un clic. Pas de spam.