← Back to Rust Course | Chapter 15: Cargo, Testing & Best Practices | Lesson 3 of 8

Writing Unit Tests

Unit tests are small checks you write to make sure a specific piece of your code keeps doing exactly what you expect.

Marking a Function as a Test

The #[test] attribute tells Cargo's test runner that a function is a test case, which it will execute and report the result of when you run cargo test.

Example: Marking a Function as a Test

markup
fn add(a: i32, b: i32) -> i32 {
    a + b
}

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

fn main() {
    println!("add(2, 3) = {}", add(2, 3));
}

Organizing Tests in a Module

Convention places unit tests in a nested module annotated with #[cfg(test)], so the test code is compiled only when running tests, not included in regular release builds.

Example: Organizing Tests in a Module

markup
fn multiply(a: i32, b: i32) -> i32 {
    a * b
}

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

    #[test]
    fn test_multiply() {
        assert_eq!(multiply(3, 4), 12);
    }
}

fn main() {
    println!("multiply(3, 4) = {}", multiply(3, 4));
}

Running Tests with cargo test

cargo test compiles the project in test mode, discovers every function marked #[test], runs them all, and prints a pass/fail summary.

Example: Running Tests with cargo test

bash
cargo test

⚠️ Run this command in your terminal.

Testing Multiple Cases

A function is often exercised by several test cases covering typical inputs, edge cases, and boundary conditions, each as its own #[test] function.

Example: Testing Multiple Cases

markup
fn is_even(n: i32) -> bool {
    n % 2 == 0
}

#[test]
fn test_even_number() {
    assert!(is_even(4));
}

#[test]
fn test_odd_number() {
    assert!(!is_even(7));
}

fn main() {
    println!("is_even(4) = {}", is_even(4));
    println!("is_even(7) = {}", is_even(7));
}
Common Mistakes
  1. Forgetting the #[test] attribute above a test function, which means cargo test will not recognize or run it.
  2. Writing test functions outside of a #[cfg(test)] module, causing them to be compiled into the regular release binary unnecessarily.
  3. Testing implementation details that change often instead of testing the public, stable behavior of a function.
Chapter Summary
  • #[test] marks a function as a test that cargo test will discover and run.
  • Tests are conventionally placed inside a #[cfg(test)] mod tests { ... } block, keeping them separate from release builds.
  • assert_eq!, assert!, and assert_ne! are the primary macros used to check expected outcomes inside tests.
  • cargo test compiles and runs every discovered test, reporting pass/fail results for each.
🔒

Chapter Quiz — Complete all 8 topics to unlock

0/8 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.