Testing
Recipe | Crates | Categories |
---|---|---|
Test your code with cargo test | ||
Emit a custom message | ||
Test your code faster with cargo nextest | ||
approx | ||
Test your code against snapshots | ||
Measure your code coverage |
Test your code with cargo test
cargo test
to run all tests.
cargo test test_prefix
to run all tests that start with the provided prefix.
cargo test -- --show-output
to show output (println!) that is otherwise captured during tests.
struct Rectangle { width: u32, height: u32, } impl Rectangle { fn can_hold(&self, _another: &Rectangle) -> bool { true } } // Put unit tests in the same file than the main code #[cfg(test)] // only for unit tests mod tests { // Access to all objects in the parent module, // which contains the main code use super::*; // Test functions must be free, monomorphic functions that take no // arguments, and commonly return () or Result<T, E> where T: // Termination, E: Debug #[test] fn larger_can_hold_smaller() { let larger = Rectangle { width: 8, height: 7, }; let smaller = Rectangle { width: 5, height: 1, }; assert!(larger.can_hold(&smaller)); // You may also use: assert_eq!(result, some_const); // or assert_ne!(...) } // This test passes if the code inside the function panics; // It fails if the code inside the function doesn't panic. #[should_panic] #[test] fn another() { panic!("Make this test fail"); } // With Result #[test] fn it_works() -> Result<(), String> { if 2 + 2 == 4 { Ok(()) // Pass if OK } else { Err(String::from("two plus two does not equal four")) } } #[ignore = "This test takes an hour to run. Only run it manually when needed"] #[test] fn expensive_test() { // Long-running code } }
Emit a custom message
fn main() { let result = "Carl"; assert!( result.contains("Carol"), "Greeting did not contain name, value was `{}`", result ); }
Test your code faster with cargo nextest
cargo-nextest
⮳ is a new, faster test runner for Rust.
cargo nextest run
cargo test --doc
approx
approx
⮳ allows approximate floating point equality comparisons and assertions.
use std::f64; use approx::assert_abs_diff_eq; use approx::assert_relative_eq; use approx::assert_ulps_eq; use approx::relative_eq; // `approx` provides facilities for testing the approximate equality of // floating-point based types, which are subject to rounding errors. // It is commonly used in tests. fn main() { let a = 1.0000001; let b = 1.0000002; // Use `assert_relative_eq` to compare the two values approximately. // It panics with a helpful error on failure. // You can specifiy the tolerance to use, and other parameters. assert_relative_eq!(a, b, epsilon = 1.0e-6); println!("The numbers are approximately equal!"); // The assertion delegates to an approximative equality macro. let _result: bool = relative_eq!(a, b); // Other methods of comparing floating-point numbers are available: // Approximate equality of using the absolute difference: assert_abs_diff_eq!(1.0, 1.0); assert_abs_diff_eq!(1.0, 1.0, epsilon = f64::EPSILON); // Approximate equality using both the absolute difference and ULPs (Units // in Last Place): assert_ulps_eq!(1.0, 1.0); }
Test your code against snapshots
Snapshots tests (also sometimes called approval tests) are tests that assert values against a reference value (the snapshot). Think of it as a supercharged version of assert_eq!
⮳. insta
lets you compare the result of a test against a reference value but, unlike simple assertions, the reference value is managed by insta
⮳ for you.
First, install the CLI with cargo install cargo-insta
. Second, create a test, run it a first time with cargo test
. This creates a snapshot file (ending with .snap
). Use cargo insta review
to review and accept the snapshot. Running cargo test
again now succeeds, until the value returned by the function under test changes.
// Snapshot testing with the `insta` crate keeps track of how your data // structures or output change over time. // This is a sample function that formats user details, // in e.g. `src/lib.rs` pub fn format_user(name: &str, age: u32) -> String { format!("Name: {}, Age: {}", name, age) } // The following is a test that uses `insta` // to snapshot the output, in e.g. `tests/snapshot.rs`. // Run with `cargo test` use insta::assert_snapshot; #[test] fn test_format_user() { let formatted = format_user("Alice", 30); // If the test fails, `insta` will prompt you to review and accept the new // snapshot. This allows you to easily manage changes to your output // over time. assert_snapshot!("format_user_snapshot", formatted); }