11.5 Using Result<T, E> in Tests
11.5.1 Test Functions That Return the Result Enum
So far, the reason tests have failed has always been a panic!, but that is not the only way a test can fail.
Tests that use the Result enum are also easy to write. You only need to accept the value returned by the code under test. If it matches expectations, return the Ok variant; otherwise return the Err variant. Since enum variants can carry data, you can also attach error information to Err to help with debugging.
If it is Ok, the test passes; otherwise it fails.
For example:
#![allow(unused)]
fn main() {
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() -> Result<(), String> {
let result = add(2, 2);
if result == 4 {
Ok(())
} else {
Err(String::from("two plus two does not equal four"))
}
}
}
}
The it_works function has the return type Result<(), String>. When the test passes, it returns Ok(()); when the test fails, it returns Err containing a String with an error message.
This test will definitely pass.
Writing tests that return Result<T, E> also lets you use the ? operator in the test body, which is convenient when any step that returns Err should fail the test.
One thing to keep in mind when using Result for tests: do not use the should_panic attribute on tests written with Result<T, E> (as discussed in 11.4. Using should_panic to Check Panics). To assert that an operation returns Err, use something like assert!(value.is_err()) instead of ?.