If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.
11.3.1 Adding Error Messages
In 11.2. Assertions (Assert), 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!andassert_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:
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"));
}
}
-
greetingtakes a string slice parameter namedname, and returns a string formed by concatenatingHello,name, and!. - The
greeting_contains_nametest function first assigns the value returned bygreeting("Carol")toresult, and then calls thecontainsmethod onresultto check whetherresultcontains"Carol".
This code passes the test as is.
Now letβs manually introduce a bug by modifying the greeting function:
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.91s
Running unittests src/lib.rs (target/debug/deps/greeter-170b942eb5bf5e3a)
running 1 test
test tests::greeting_contains_name ... FAILED
failures:
---- tests::greeting_contains_name stdout ----
thread 'tests::greeting_contains_name' 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:
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.93s
Running unittests src/lib.rs (target/debug/deps/greeter-170b942eb5bf5e3a)
running 1 test
test tests::greeting_contains_name ... FAILED
failures:
---- tests::greeting_contains_name stdout ----
thread 'tests::greeting_contains_name' 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.
Top comments (0)