Controlling How Tests Are Run

francescoxx

Francesco Ciulla

Posted on August 6, 2024

Controlling How Tests Are Run

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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));
    }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

But if you only care about the one_hundred test, you can run just that one:

$ cargo test one_hundred

Enter fullscreen mode Exit fullscreen mode

You can also run multiple tests that share part of their name, like this:

$ cargo test add
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

Running cargo test will skip the expensive_test, but you can run it specifically with the following:

$ cargo test -- --ignored
Enter fullscreen mode Exit fullscreen mode

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

💖 💪 🙅 🚩
francescoxx
Francesco Ciulla

Posted on August 6, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

All the Rust Features
programming All the Rust Features

November 1, 2024

Iterators in Rust - Map, Filter, Reduce
programming Iterators in Rust - Map, Filter, Reduce

October 15, 2024

Iterators in Rust
programming Iterators in Rust

October 15, 2024

Closures in Rust
programming Closures in Rust

October 6, 2024