Unit Testing

#[test]

The #[test] attribute marks a zero-argument Rust function as a test case to be registered and executed by the rustc --test harness. Functions marked with #[test] are omitted from normal cargo build and cargo run compilations and are only compiled when building in test mode (cargo test).

#[test]
fn my_test_case() -> ()  or  Result<(), E>
       |
       +-- Compiled under `cargo build`?  NO (stripped by compiler)
       +-- Compiled under `cargo test`?   YES (registered in libtest runner)

Supported Function Signatures for #[test]

A function annotated with #[test] must take zero parameters (fn()) and have one of two return types:

  1. Unit () (default): Passes if the function finishes without panicking; fails if a panic occurs.
  2. Result<(), E> where E: std::fmt::Debug (any Termination type): Passes on Ok(()) and fails on Err(e) (printing "Error: {e:?}"), allowing ergonomic use of the ? operator inside tests without .unwrap().
use std::num::ParseIntError;

fn parse_pair(input: &str) -> Result<(i32, i32), ParseIntError> {
    let (left, right) = input.split_once(',').unwrap_or((input, "0"));
    Ok((left.trim().parse()?, right.trim().parse()?))
}

#[test]
fn test_with_assertions() {
    assert_eq!(parse_pair("10, 20"), Ok((10, 20)));
}

#[test]
fn test_with_question_mark() -> Result<(), ParseIntError> {
    let (x, y) = parse_pair("30, 40")?;
    assert_eq!(x + y, 70);
    Ok(())
}

fn main() {
    println!("Parsed pair: {:?}", parse_pair("10, 20").unwrap());
}
Parsed pair: (10, 20)

Running cargo test executes both test functions:

running 2 tests
test test_with_assertions ... ok
test test_with_question_mark ... ok

test result: ok. 2 passed; 0 failed; 0 filtered out; finished in 0.00s

Compile-Time Restrictions on #[test] Functions

A #[test] function cannot accept parameters or generic type arguments because the test runner invokes it directly without arguments:

// ❌ does not compile
#[test]
fn invalid_parameterized_test(input: i32) {
    assert!(input > 0);
}
error: functions used as tests can not have any arguments
 --> src/lib.rs:2:1
  |
2 | #[test]
  | ------- in this attribute macro expansion
3 | fn invalid_parameterized_test(input: i32) {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Note that #[test] and #[should_panic] cannot be combined with a Result<(), E> return type—#[should_panic] tests must return ().