🎓 A1Learner
🔍

Rust Test Assertions

Test assertions are the checks that compare a result with what it should be. assert_eq! checks that two values are equal.

Equal is not the only question

assert_ne! It requires two values to be different. Use it when the wrong result is clear but the exact result is not. assert! checks any condition you can write:

assert_ne!(greeting("Carol"), "");
assert!(greeting("Carol").contains("Carol"));

A failed check shows both values

When assert_eq! or assert_ne! fails, the report prints the two values as left and right, so you can see what went wrong:

assert_eq!(greeting("Carol"), "Hello, Ana!");

Say what the check meant

Extra arguments after the condition work like format! arguments. They appear in the failure report and explain what the check meant:

let r = greeting("Carol");
assert!(r.contains("Carol"), "greeting was `{r}`");

Your own types can join in

The compared values must implement PartialEq and Debug. For your own structs and enums, derive both:

#[derive(PartialEq, Debug)]
struct Score {
    points: i32,
}

Pin the panic to its reason

Plain #[should_panic] passes on any panic at all — even one for the wrong reason. expected also requires the panic message to contain your text:

#[test]
#[should_panic(expected = "between 1 and 100")]
fn guess_too_big() {
    check_guess(200);
}

Compare decimals with a gap

Decimal fractions are stored as binary guesses. 0.1 + 0.2 does not equal 0.3 exactly. assert_eq! would fail a correct programme:

#[test]
fn prices_add_up() {
    let total: f64 = 0.1 + 0.2;
    assert!((total - 0.3).abs() < 1e-9);
}

Example

fn greeting(name: &str) -> String { format!("Hello, {name}!") }
fn check_guess(value: i32) { if value < 1 || value > 100 { panic!("Guess must be between 1 and 100, got {value}."); } }
#[cfg(test)]
mod tests {
    use super::*;
    #[test] fn greeting_has_name() { let r = greeting("Carol"); assert!(r.contains("Carol"), "greeting was `{r}`"); }
    #[test] fn greeting_is_not_empty() { assert_ne!(greeting("Carol"), ""); }
    #[test] #[should_panic(expected = "between 1 and 100")] fn guess_too_big() { check_guess(200); }
}
fn main() { check_guess(42); println!("{} / guess 42 is fine", greeting("Carol")); }

Key points

  • Use a gap check for f32 and f64 results.
  • Exact equality asks the wrong question of a binary fraction.
  • Prefer assert_eq! or assert_ne! when two values are involved — the printed pair is the clue you will want later.
  • An assertion passes when the result matches the expected value and fails when it does not.

In this example, three tests check one small program in three sharper ways. greeting_has_name uses assert! with a custom message: if the greeting ever lost the name, the failure would print the greeting it actually got. greeting_is_not_empty uses assert_ne! to require the greeting to differ from an empty string. guess_too_big uses should_panic with expected. check_guess(200) must panic. The panic message must contain "between 1 and 100". A panic for any other reason would fail this test. main itself calls check_guess(42), which is inside the range, so nothing panics and the greeting prints.

Note

assert! only reports that a check was false.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

What does #[should_panic(expected = "too big")] add to a panic test?