Testing

Test your code with cargo test

cargo cargo-crates.io cargo-github cargo-lib.rs

cargo test to run all tests. cargo test test_prefix to run all tests that start with the provided prefix. cargo test -- --show-output to show output (println!) that is otherwise captured during tests.


struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn can_hold(&self, _another: &Rectangle) -> bool {
        true
    }
}

// Put unit tests in the same file than the main code

#[cfg(test)] // only for unit tests
mod tests {
    // Access to all objects in the parent module,
    // which contains the main code
    use super::*;

    // Test functions must be free, monomorphic functions that take no
    // arguments, and commonly return () or Result<T, E> where T:
    // Termination, E: Debug

    #[test]
    fn larger_can_hold_smaller() {
        let larger = Rectangle {
            width: 8,
            height: 7,
        };
        let smaller = Rectangle {
            width: 5,
            height: 1,
        };

        assert!(larger.can_hold(&smaller));
        // You may also use: assert_eq!(result, some_const);
        // or assert_ne!(...)
    }

    // This test passes if the code inside the function panics;
    // It fails if the code inside the function doesn't panic.

    #[should_panic]
    #[test]
    fn another() {
        panic!("Make this test fail");
    }

    // With Result

    #[test]
    fn it_works() -> Result<(), String> {
        if 2 + 2 == 4 {
            Ok(()) // Pass if OK
        } else {
            Err(String::from("two plus two does not equal four"))
        }
    }

    #[ignore = "This test takes an hour to run. Only run it manually when needed"]
    #[test]
    fn expensive_test() {
        // Long-running code
    }
}

Emit a custom message

std cat-development-tools cat-development-tools::testing

fn main() {
    let result = "Carl";

    assert!(
        result.contains("Carol"),
        "Greeting did not contain name, value was `{}`",
        result
    );
}

Test your code faster with cargo nextest

cargo-nextest cargo-nextest-crates.io cargo-nextest-github cargo-nextest-lib.rs cat-development-tools

cargo-nextest⮳ is a new, faster test runner for Rust.

cargo nextest run
cargo test --doc

approx

approx approx-crates.io approx-github approx-lib.rs cat-development-tools::testing

approx⮳ allows approximate floating point equality comparisons and assertions.

use std::f64;

use approx::assert_abs_diff_eq;
use approx::assert_relative_eq;
use approx::assert_ulps_eq;
use approx::relative_eq;

// `approx` provides facilities for testing the approximate equality of
// floating-point based types, which are subject to rounding errors.
// It is commonly used in tests.
fn main() {
    let a = 1.0000001;
    let b = 1.0000002;

    // Use `assert_relative_eq` to compare the two values approximately.
    // It panics with a helpful error on failure.
    // You can specifiy the tolerance to use, and other parameters.
    assert_relative_eq!(a, b, epsilon = 1.0e-6);
    println!("The numbers are approximately equal!");

    // The assertion delegates to an approximative equality macro.
    let _result: bool = relative_eq!(a, b);

    // Other methods of comparing floating-point numbers are available:

    // Approximate equality of using the absolute difference:
    assert_abs_diff_eq!(1.0, 1.0);
    assert_abs_diff_eq!(1.0, 1.0, epsilon = f64::EPSILON);

    // Approximate equality using both the absolute difference and ULPs (Units
    // in Last Place):
    assert_ulps_eq!(1.0, 1.0);
}

Test your code against snapshots

insta insta-crates.io insta-github insta-lib.rs cat-development-tools::testing

cargo-insta cargo-insta-crates.io cargo-insta-github cargo-insta-lib.rs cat-development-tools::cargo-plugins

Snapshots tests (also sometimes called approval tests) are tests that assert values against a reference value (the snapshot). Think of it as a supercharged version of assert_eq!. insta lets you compare the result of a test against a reference value but, unlike simple assertions, the reference value is managed by insta for you.

First, install the CLI with cargo install cargo-insta. Second, create a test, run it a first time with cargo test. This creates a snapshot file (ending with .snap). Use cargo insta review to review and accept the snapshot. Running cargo test again now succeeds, until the value returned by the function under test changes.


// Snapshot testing with the `insta` crate keeps track of how your data
// structures or output change over time.

// This is a sample function that formats user details,
// in e.g. `src/lib.rs`
pub fn format_user(name: &str, age: u32) -> String {
    format!("Name: {}, Age: {}", name, age)
}

// The following is a test that uses `insta`
// to snapshot the output, in e.g. `tests/snapshot.rs`.
// Run with `cargo test`

use insta::assert_snapshot;

#[test]
fn test_format_user() {
    let formatted = format_user("Alice", 30);
    // If the test fails, `insta` will prompt you to review and accept the new
    // snapshot. This allows you to easily manage changes to your output
    // over time.
    assert_snapshot!("format_user_snapshot", formatted);
}

Measure your code coverage

cargo_tarpaulin-github cat-development-tools cat-development-tools::cargo-plugins