Testing is an essential part of software development, especially when coding professionally and improving your code's quality.
In Rust, testing is built into the language, making writing and running tests straightforward.
This article will introduce you to the basics of testing in Rust with practical examples.
Create the lib project
In this case, we will create a library project using the following command:
cargo new adder --lib
Remember to use the --bin flag to create a binary project.
To run the tests, you can use the following command:
cargo test
This command will compile the code and run the tests.
Now let's create a simple function to test.
Basic Test Function
Let's start with a simple test function. In Rust, test functions are annotated with #[test].
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
In this example, the #[cfg(test)] attribute ensures that the test module is only compiled when running tests. The #[test] attribute marks the function as a test.
The assert_eq! macro checks if the two arguments are equal. If they are not, the test will fail.
The output of the test will look like this:
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Making a Test That Fails
It's often useful to see what happens when a test fails.
Here's an example:
#[cfg(test)]
mod tests {
#[test]
fn it_fails() {
assert_eq!(2 + 2, 5);
}
}
When you run this test, it will fail, and you'll see an error message like this:
---- it_fails stdout ----
thread 'tests::it_fails' panicked at 'assertion failed: `(left == right)`
left: `4`,
right: `5`', src/lib.rs:4:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Using the assert! Macro
The assert! macro is used to check boolean expressions. If the expression evaluates to false, the test will fail.
#[cfg(test)]
mod tests {
#[test]
fn check_true() {
assert!(true);
}
}
Testing Equality with assert_eq! and assert_ne!
The assert_eq! macro checks if two values are equal, while assert_ne! checks if they are not.
#[cfg(test)]
mod tests {
#[test]
fn test_equality() {
assert_eq!(3 * 3, 9);
assert_ne!(3 * 3, 8);
}
}
Adding Custom Failure Messages
You can add custom failure messages to your tests using the assert! macro.
#[cfg(test)]
mod tests {
#[test]
fn custom_message() {
assert_eq!(2 + 2, 5, "Math is broken!");
}
}
In this example, the test will fail with the message "Math is broken!".
The output will look like this:
---- custom_message stdout ----
thread 'tests::custom_message' panicked at 'assertion failed: `(left == right)`
left: `4`,
right: `5`: Math is broken!', src/lib.rs:4:9
Checking for Panics with should_panic
You can test if a function panics using the should_panic attribute.
#[cfg(test)]
mod tests {
#[test]
#[should_panic]
fn it_panics() {
panic!("This test will panic");
}
}
Using Result in Tests
Test functions can return Result<(), E> to use the ? operator for error handling.
#[cfg(test)]
mod tests {
#[test]
fn test_with_result() -> Result<(), String> {
if 2 + 2 == 4 {
Ok(())
} else {
Err("Math is broken".into())
}
}
}
Conclusion
Rust makes testing easy and powerful with its built-in features.
By using attributes like #[test], assert!, assert_eq!, and should_panic, you can write robust tests for your code.