Sling Academy
Home/Rust/Filtering and Selecting Specific Tests to Run in Rust

Filtering and Selecting Specific Tests to Run in Rust

Last updated: January 06, 2025

When developing in Rust, it’s essential to test our code efficiently to ensure reliability and correctness. An arsenal of testing tools is provided within the language that allows developers to maintain rigorous standards. However, as projects grow in size, it's not always practical or efficient to run all tests every single time. In these scenarios, knowing how to filter and select specific tests to run can save time and resources.

Understanding Rust’s Testing Framework

Rust’s built-in testing framework simplifies the testing process by integrating directly into the language. Standard Rust tests are implemented as functions that utilize the #[test] attribute. By running cargo test, these functions are automatically executed. Here is the simplest form of a test in Rust:


#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}

Running tests with cargo test executes all tests in your project. But what if you want to run a specific test? That’s where filtering and selection come into play.

Filtering Tests by Name

One of the easiest ways to narrow down the number of tests run is by providing a pattern that matches the name of the tests you wish to execute. For example, suppose we extend our test module:


#[cfg(test)]
mod tests {
    #[test]
    fn test_addition() {
        assert_eq!(1 + 1, 2);
    }
    
    #[test]
    fn test_subtraction() {
        assert_eq!(2 - 1, 1);
    }
}

To run only the test for addition, you would use the following command:


cargo test test_addition

This will execute only the tests that contain the substring "test_addition" in their names. Similarly, any partial match will run tests with names that include that pattern.

Running Ignored Tests

Sometimes, there are tests that may take too long to run under normal circumstances, so we mark them as ignored to exclude them from standard test execution. To achieve this, the #[ignore] attribute is used:


#[cfg(test)]
mod tests {
    #[test]
    #[ignore]
    fn expensive_test() {
        // Simulate a heavy computation
        assert_eq!( expensive_computation(), true);
    }
}

cargo test will not run expensive_test by default. However, you can include ignored tests during execution like so:


cargo test -- --ignored

By separating tests in this manner, it's easy to manage test execution based on context or necessity.

Grouping Tests with Test Suites

While filtering by name is a straightforward method, Rust also allows you to organize tests into test suites for better structure and control. Test suites can be implemented using submodules or different files in the tests directory for integration tests:


// src/lib.rs
#[cfg(test)]
mod integration_tests {
    mod suite1 {
        #[test]
        fn basic_test() {
            assert!(true);
        }
    }
    mod suite2 {
        #[test]
        fn complex_test() {
            assert!(1 + 1 == 2);
        }
    }
}

This setup allows selective execution of test sets by running:


cargo test suite1

This command will only run the tests included in suite1, showcasing efficient test management for larger projects.

Conclusion

Mastering the filtering and selection of tests can significantly enhance productivity and performance in Rust development. By tailoring test runs to focus only on relevant sections of code, developers can expedite the feedback loop, helping maintain high standards without sacrificing time. Utilize these techniques in conjunction with Rust’s powerful cargo tool to develop more efficiently and focus resources where they are most needed.

Next Article: Collecting Test Coverage in Rust with cargo tarpaulin

Previous Article: Controlling Test Execution with #[ignore] in Rust

Series: Testing in Rust

Rust

You May Also Like

  • E0557 in Rust: Feature Has Been Removed or Is Unavailable in the Stable Channel
  • Network Protocol Handling Concurrency in Rust with async/await
  • Using the anyhow and thiserror Crates for Better Rust Error Tests
  • Rust - Investigating partial moves when pattern matching on vector or HashMap elements
  • Rust - Handling nested or hierarchical HashMaps for complex data relationships
  • Rust - Combining multiple HashMaps by merging keys and values
  • Composing Functionality in Rust Through Multiple Trait Bounds
  • E0437 in Rust: Unexpected `#` in macro invocation or attribute
  • Integrating I/O and Networking in Rust’s Async Concurrency
  • E0178 in Rust: Conflicting implementations of the same trait for a type
  • Utilizing a Reactor Pattern in Rust for Event-Driven Architectures
  • Parallelizing CPU-Intensive Work with Rust’s rayon Crate
  • Managing WebSocket Connections in Rust for Real-Time Apps
  • Downloading Files in Rust via HTTP for CLI Tools
  • Mocking Network Calls in Rust Tests with the surf or reqwest Crates
  • Rust - Designing advanced concurrency abstractions using generic channels or locks
  • Managing code expansion in debug builds with heavy usage of generics in Rust
  • Implementing parse-from-string logic for generic numeric types in Rust
  • Rust.- Refining trait bounds at implementation time for more specialized behavior