Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

11.3 Custom Error Messages

11.3.1 Adding Error Messages

In 11.2. Assertions, we learned about the assert!, assert_eq!, and assert_ne! macros, and this article covers their advanced usage.

These three macros can accept custom error messages, but that is optional. If you add a custom message, it will be printed together with the standard failure message:

  • For assert!, the first argument is required and the custom message is the second argument.
  • For assert_eq! and assert_ne!, the first two arguments are required and the custom message is the third argument.

After you pass in the custom message, it will be sent to the format! macro to build a string. Since format! can use {} placeholders, the message you pass in can also use placeholders.

For example:

#![allow(unused)]
fn main() {
pub fn greeting(name: &str) -> String {
    format!("Hello {name}!")
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn greeting_contains_name() {
        let result = greeting("Carol");
        assert!(result.contains("Carol"));
    }
}
}
  • greeting takes a string slice parameter named name, and returns a string formed by concatenating Hello, name, and !.
  • The greeting_contains_name test function first assigns the value returned by greeting("Carol") to result, and then calls the contains method on result to check whether result contains "Carol".

This code passes the test as is.

Now let’s manually introduce a bug by modifying the greeting function:

#![allow(unused)]
fn main() {
pub fn greeting(name: &str) -> String {
    format!("Hello!")
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn greeting_contains_name() {
        let result = greeting("Carol");
        assert!(result.contains("Carol"));
    }
}
}

This test will fail:

$ cargo test
   Compiling greeter v0.1.0 (file:///projects/greeter)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.14s
     Running unittests src/lib.rs (target/debug/deps/greeter-647141eed08f233c)

running 1 test
test tests::greeting_contains_name ... FAILED

failures:

---- tests::greeting_contains_name stdout ----

thread 'tests::greeting_contains_name' (455732) panicked at src/lib.rs:12:9:
assertion failed: result.contains("Carol")
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::greeting_contains_name

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`

However, the failure message only says that a panic occurred at line 12, column 9. It does not provide friendlier or more useful information. What should we do? Add a custom message:

#![allow(unused)]
fn main() {
pub fn greeting(name: &str) -> String {
    format!("Hello!")
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn greeting_contains_name() {
        let result = greeting("Carol");
        assert!(
            result.contains("Carol"),
            "Greeting did not contain name, value was `{result}`"
        );
    }
}
}

Output:

$ cargo test
   Compiling greeter v0.1.0 (file:///projects/greeter)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.09s
     Running unittests src/lib.rs (target/debug/deps/greeter-647141eed08f233c)

running 1 test
test tests::greeting_contains_name ... FAILED

failures:

---- tests::greeting_contains_name stdout ----

thread 'tests::greeting_contains_name' (456094) panicked at src/lib.rs:12:9:
Greeting did not contain name, value was `Hello!`
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::greeting_contains_name

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`

You can see that the custom message appears in the error output. Such messages are more meaningful in practice, which makes it easier to find the cause of the error.