Controlling How Tests Are Run
Francesco Ciulla
Posted on August 6, 2024
Like cargo run
compiles and runs your code, cargo test
compiles your code in test mode and then runs the test binary.
By default, it runs all the tests in parallel and hides the output, so you only see the test results. But you can change this behavior with a few command-line options.
Some options are for cargo test itself, while others are for the test binary it produces. To differentiate, you list the cargo test options first, followed by --, and then the options for the test binary.
For example, you can see the available options by running:
$ cargo test --help
$ cargo test -- --help
If you prefer a video version
For a Full Free Rust Course:
Running Tests in Parallel or One by One
When you run multiple tests, they run in parallel by default, making the process faster. But since tests run simultaneously, they shouldn’t depend on each other or share any state (like files or environment variables).
For instance, imagine each test creates a file named test-output.txt and writes some data. If two tests run simultaneously, one might overwrite the file while the other tries to read it, causing a test to fail.
You can solve this by giving each test a unique file or by running tests one at a time like this:
$ cargo test -- --test-threads=1
This command sets the number of test threads to 1, meaning there is no parallelism. It’s slower, but it avoids interference.
Seeing Output from Passing Tests
By default, Rust captures any println! output from tests that pass, showing only what gets printed when a test fails.
For example, consider this code:
fn prints_and_returns_10(a: i32) -> i32 {
println!("I got the value {a}");
10
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn this_test_will_pass() {
let value = prints_and_returns_10(4);
assert_eq!(10, value);
}
#[test]
fn this_test_will_fail() {
let value = prints_and_returns_10(8);
assert_eq!(5, value);
}
}
Running cargo test would produce:
$ cargo test
Compiling silly-function v0.1.0 (file:///projects/silly-function)
Finished test [unoptimized + debuginfo] target(s) in 0.58s
Running unittests src/lib.rs (target/debug/deps/silly_function-160869f38cff9166)
running 2 tests
test tests::this_test_will_fail ... FAILED
test tests::this_test_will_pass ... ok
failures:
---- tests::this_test_will_fail stdout ----
I got the value 8
thread 'tests::this_test_will_fail' panicked at src/lib.rs:19:9:
assertion `left == right` failed
left: 5
right: 10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
tests::this_test_will_fail
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Notice that the output from the passing test (I got the value 4) doesn’t appear. If you want to see the output from all tests, use the --show-output flag:
$ cargo test -- --show-output
Running Specific Tests
Sometimes, running all tests isn’t necessary, especially if you’re working on one part of your code.
For example, suppose to have these tests:
pub fn add_two(a: i32) -> i32 {
a + 2
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn add_two_and_two() {
assert_eq!(4, add_two(2));
}
#[test]
fn add_three_and_two() {
assert_eq!(5, add_two(3));
}
#[test]
fn one_hundred() {
assert_eq!(102, add_two(100));
}
}
Running cargo test
will run all the tests, as usual.
$ cargo test
Compiling adder v0.1.0 (file:///projects/adder)
Finished test [unoptimized + debuginfo] target(s) in 0.62s
Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)
running 3 tests
test tests::add_three_and_two ... ok
test tests::add_two_and_two ... ok
test tests::one_hundred ... ok
But if you only care about the one_hundred test, you can run just that one:
$ cargo test one_hundred
You can also run multiple tests that share part of their name, like this:
$ cargo test add
This will run any test with "add" in its name.
Ignoring Slow Tests
If you have tests that take a long time to run, you can exclude them by using the #[ignore] attribute:
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
#[test]
#[ignore]
fn expensive_test() {
// code that takes an hour to run
}
Running cargo test will skip the expensive_test, but you can run it specifically with the following:
$ cargo test -- --ignored
This lets you keep your tests quick during regular development, while still allowing you to run the longer tests when needed.
Conclusion
cargo test is a powerful tool for running your tests, and it has many options to help you control how your tests run.
You can run tests in parallel or one by one, see output from passing tests, run specific tests, and ignore slow tests, and much more!
If you prefer a video version
For a Full Free Rust Course:
All the links about me are here: https://francescociulla.com
Posted on August 6, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.