In the Rust programming language, we use test functions to test the non-test code in a program.
We can use a test function using three main steps:
Writing test cases can help us find if any part of the code is working or not.
To write a test function, it is necessary to add an attribute #[test]
before the start of the test function. Rust creates a binary file for the piece of code that includes the #[test]
annotation.
#[test]fn success(){//The body of the test function}
To test the code, we can write multiple test cases. We can run a test case by using the following command:
cargo test
The cargo test
command executes the test functions that we write.
Let’s write our own test function with the help of an example project.
cargo new project
The new
command creates a new directory, project
. Our project directory contains the main.rs
file.
main.rs
file.mod test;fn check_even_num(value:i32) -> bool {if value % 2 == 0{true}else{false}}
test.rs
file to write the test function.use crate::check_even_num;#[test]fn success(){assert!(check_even_num(4));}#[test]fn check_failure(){assert_eq!(check_even_num(3),false);}
main.rs
file by adding the following line:mod test;
cargo test
It shows the following output:
Compiling project v0.1.0 (/project)Finished test [unoptimized + debuginfo] target(s) in 0.50sRunning unittests src/main.rs (/project/target/debug/deps/project-04898232a9e03d49)running 2 teststest test::check_failure ... oktest test::success ... oktest result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
We can run the cargo test
command below and hit the "Run" button to see the terminal.
[package] name = "project" version = "0.1.0" authors = ["Laraib"] [dependencies]
In the main.rs
file, mod test;
is added to include the test file.
In the test.rs
file, we do the following:
#[test]
to specify this is a test case i.e., success()
and check_failure.
success()
function, we use assert()
. This passes the test if a true value is passed to it.check_failure()
test case, assert_eq!()
compares the two values and passes the test case if they match.We use the #[should_panic]
attribute when we try to write a condition where a function should panic. One example is when we write a function for division, and we create a panic case when the user inputs zero value for the denominator.
In the scenario where we write multiple test cases, we use the #[ignore]
attribute to exclude the cases we don’t want to execute.
We can understand this by looking at an example.
pub fn nonZeroDivision(a: u32, b: u32) -> u32 { if b == 0 { panic!("Divide-by-zero error"); } else if a < b { panic!("Divide result is zero"); } a / b } #[cfg(test)] mod tests { use super::*; #[test] fn test_divide() { assert_eq!(nonZeroDivision(10, 2), 5); } #[test] #[should_panic] fn test_any_panic() { nonZeroDivision(1, 0); } #[test] #[should_panic(expected = "Divide result is zero")] fn test_specific_panic() { nonZeroDivision(1, 10); } }
should_panic
keyword to throw panic
when the function gets zero
as the denominator value.[ignore]
keyword before the test case. This will ignore the individual test case when running the test cases for the function.Free Resources