100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Rust

Testing in Rust

Learn Rust's built-in testing framework, from #[test] functions and assertion macros to unit and integration test organization.

Concurrency & ToolingIntermediate9 min readJul 8, 2026
Analogies

Introduction

Rust has a testing framework built directly into the language and Cargo, so you don't need a third-party library to write and run tests. Functions annotated with the #[test] attribute become test cases, and cargo test compiles the project in test mode and runs every test, reporting pass/fail results. Rust distinguishes between unit tests, which live alongside the code they test, and integration tests, which live in a separate top-level tests/ directory and exercise the crate's public API as an external user would.

🏏

Cricket analogy: Cargo's built-in testing is like the BCCI having its own official umpiring system rather than hiring an outside agency; #[test] functions are like scheduled practice matches, and cargo test runs the full nets session and reports who's match-fit.

Syntax

rust
#[test]
fn it_works() {
    assert!(true);
}

#[test]
fn checks_equality() {
    assert_eq!(2 + 2, 4);
    assert_ne!(2 + 2, 5);
}

#[test]
#[should_panic]
fn it_panics() {
    panic!("expected failure");
}

Explanation

The #[test] attribute marks a function as a test case; cargo test discovers and runs every such function, printing ok or FAILED for each along with a summary. The assert! macro panics (failing the test) if its argument is false; assert_eq! and assert_ne! compare two values and panic with a helpful diff-style message if they are unexpectedly equal or unequal. Unit tests are conventionally placed in the same file as the code under test, inside a submodule annotated #[cfg(test)] named mod tests, which brings the parent module's items into scope with use super::*; the #[cfg(test)] attribute tells the compiler to only compile that module when running tests, keeping test code out of release builds. Integration tests instead live in files under a top-level tests/ directory; each file there is compiled as its own separate crate that only sees the library's public API, so they test the crate the way an external consumer would. The #[should_panic] attribute marks a test as passing only if the annotated function panics, which is useful for verifying error conditions.

🏏

Cricket analogy: assert_eq! is like a third umpire's DRS review comparing the ball-tracking prediction to the actual impact and flashing a detailed replay if they disagree; #[cfg(test)] mod tests is like a practice-only net kept off the main stadium pitch on match day.

Example

rust
// src/lib.rs
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn adds_two_numbers() {
        assert_eq!(add(2, 3), 5);
    }

    #[test]
    #[should_panic]
    fn wrong_result_panics() {
        assert_eq!(add(2, 2), 5, "math is broken");
    }
}

Output

bash
$ cargo test
running 2 tests
test tests::adds_two_numbers ... ok
test tests::wrong_result_panics ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Key Takeaways

  • The #[test] attribute marks a function as a test case, run via cargo test.
  • assert!, assert_eq!, and assert_ne! are the core assertion macros for verifying behavior.
  • Unit tests typically live in a #[cfg(test)] mod tests submodule alongside the code they test.
  • Integration tests live in a top-level tests/ directory and exercise only the crate's public API.
  • #[should_panic] marks a test as passing only when the function panics, useful for testing error paths.

Practice what you learned

Was this page helpful?

Topics covered

#Rust#RustProgrammingStudyNotes#Programming#TestingInRust#Testing#Syntax#Explanation#Example#StudyNotes#SkillVeris