---
title: Cours de programmation séquentielle
subtitle: Tests automatiques
author: Orestis Malaspinas
sansfont: Sans Serif
---

# Tests automatiques

## A quoi ça sert?

- Nous permet d'avoir confiance en nos programmes.
- Tester que notre programme se comporte comme désiré.
- Le compilateur ne peut pas détecter tous les bugs possibles: les erreurs algorithmiques ne peuvent pas être détectées.
- Éviter les *régressions* lorsqu'on réécrit ou étend les fonctionalités d'un programme.
- Néanmois: **impossible** de tester si un programme est complètement correct (on ne peut pas tester *tous les cas*).
- Plus de détails et d'informations: [ici](https://doc.rust-lang.org/book/second-edition/ch11-00-testing.html)

## Comment écrire un test

En général un test effectue les trois actions suivantes:

1. Mettre en place les données ou un état donné.
2. Exécuter le code à tester.
3. Vérifier si le résultat est celui attendu.

## Exemple

- Il est très aisé de voir l'anatomie d'un test très simple:
<pre><code data-trim="bash">
cargo new projet_test --lib
</code></pre>

- Création d'un projet avec le fichier `projet_test/src/lib.rs`
<pre><code data-trim="hljs rust">
    #[cfg(test)] // cette partie sera exécuté que lors du test
mod tests {
    #[test] // la fonction suivant cette annotation sera exécutée comme test
    fn it_works() {
        assert_eq!(2 + 2, 4); // Vérification que l'addition fonctionne pour 2+2
        assert_ne!(2 + 2, 6); // utilisation de assert_ne!
        assert!(2 + 2 == 4); // utilisation de assert! 2+2
    }
}
</code></pre>

- Le test est exécuté avec `cargo test`
<pre><code data-trim="bash">
   Compiling projet_test v0.1.0 (projet_test)
    Finished dev [unoptimized + debuginfo] target(s) in 0.45s
     Running projet_test/target/debug/deps/projet_test-05539f5503f2a0fe\
\
running 1 test
test tests::it_works ... ok\
\
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out\
\
   Doc-tests projet_test\
\
running 0 tests\
\
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
</code></pre>

## Tests de fonctions

- Le test d'une fonction nécessite de la mettre dans la porté

<pre><code data-trim="hljs rust">
    fn add_two(a: i32) -> i32 {
    a + 2
}

#[cfg(test)]
mod tests {
    use super::*; // mise en portée de tout ce qui est dans le module de dessus

    #[test]
    fn test_add_two() {
        assert_eq!(add_two(2), 4); // Vérification de la fonction add_two
    }

    #[test]
    fn test_add_two_custom_msg() {
        // Ce test va paniquer à dessein, pour voir le message personnalisé. 
        assert_eq!(add_two(2) == 5, "Attention la somme 2+2 ne donne pas 5 mais {}.", 4);
    }
}
</code></pre>

## Tests devant paniquer

- Si une erreur de logique est suffisamment grave pour faire paniquer le code on peut la panique:

<pre><code data-trim="hljs rust">
    fn two_div_by(a: i32) -> i32 {
    if a == 0 {
        panic!("On nee peut pas diviser par zéro.");
    } else {
        return 2 / a;
    }
}

#[cfg(test)]
mod tests {
    use super::*; // mise en portée de tout ce qui est dans le module de dessus

    #[test]
    #[should_panic] // ce test doit paniquer, s'il panique pas il est raté
    fn two_div_fail() {
        two_div_by(0);
    }
}
</code></pre>

## Affichage

- Les tests n'affichent rien si le test est réussi (la sortie standard est capturée).
- Si le test est raté, le message d'erreur et tout ce qui aurait dû être affiché à l'écran.
- Les tests sont effectués en parallèle pour des question d'efficacité:
    - L'affichage à l'écran peut s'en retrouver perturbé (affichage dans un ordre erratique).
    - Pour les exécuter séquentiellement: `cargo test --test-threads=1`.
- Pour afficher tout ce qui devrait être affiché à l'écran dans le bon ordre (même les tests réussis): 
    - `cargo test -- --nocapture --test-threads=1`

## Fonctionalités supplémentaires (voir le livre)

- Tests d'intégration:
    - On peut grouper les tests par fonctions.
    - On peut grouper les tests par sous-modules.
    - On peut tester les sous-modules indépendamment.
