[Rust Series 17] Testing and Documentation

한국어 버전

What You'll Learn

Testing and documentation are the most direct ways to make code trustworthy. We'll walk through the cargo test workflow, how to build #[test] functions, and how to leave runnable examples in doc comments.

Exploring cargo test

Any Rust project starts with a working cargo test setup by default.

cargo new calculator
cd calculator
cargo test

The template already includes a sample test, so you'll immediately see the runner execute. As long as nothing fails, you'll get the runtime, test count, and package name instead of an error report.

Writing #[test] Functions

Let's add a library function and a matching test to 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);
    }
}
  • The #[cfg(test)] module compiles only during cargo test, keeping the release binary slimmer.
  • Functions tagged with #[test] don't return values, and any panic marks the test as failed.

The assert_eq! macro compares the actual and expected values. When it fails, it shows both values plus the source location, which makes debugging quick.

Code inside doc comments is also a form of testing. Every documented example doubles as runnable verification, and that's one of Rust's biggest wins.

Testing Edge Cases

When you write multiple tests for the same function, choose descriptive scenario names so future refactors keep their meaning.

#[test]
fn add_handles_negative() {
    assert_eq!(add(-3, 1), -2);
}

#[test]
fn add_with_zero_returns_other() {
    assert_eq!(add(0, 7), 7);
}

If someone can infer the inputs just by reading the test names, they'll also understand failure logs more quickly.

Doc Comments and Examples

Any library you expect others to consume needs doc comments (///). Embed code blocks inside those comments, and cargo test will execute them for you.

/// Returns the sum of two integers.
///
/// # Examples
///
/// ```
/// use calculator::add;
/// assert_eq!(add(2, 2), 4);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

Doctests are lifesavers when maintaining real usage examples. If the implementation changes, outdated samples fail immediately, keeping documentation and code in sync.

cargo doc --open

Run the following command whenever you want an HTML preview of your docs:

cargo doc --open

It documents the public API of your project and opens it in the default browser. Items that aren't pub stay hidden, so be intentional about what you expose.

Common Pitfalls

  • Declaring parameters on a #[test] function causes a compile error; tests can't take arguments.
  • Async tests need a runtime such as #[tokio::test]. We focus on synchronous tests here.
  • Use cargo test -- --nocapture to see println! output; the default hides logs when tests pass.
  • If interleaved output is confusing, run cargo test -- --test-threads=1 to execute tests sequentially.

Practice in CodeSandbox

The sandbox below uses CodeSandbox's Rust starter. Move the main code into src/main.rs, then compare cargo check and cargo run so you can read the compiler feedback beside the final output.

Live Practice

Rust Practice Sandbox

CodeSandbox

Run the starter project in CodeSandbox, compare it with the lesson code, and keep experimenting.

Rust startercargoterminal
  1. Fork the starter and open src/main.rs
  2. Paste the lesson code and run cargo check plus cargo run in order
  3. Change types, values, or borrowing flow and compare the compiler feedback with the output

Rust practice here is mainly terminal-driven rather than browser-preview driven. Lessons that need multiple files or extra crates may require a bit more setup inside the starter.

Practice

  1. Implement subtract and add two tests that cover positive and negative inputs.
  2. Execute only one test with cargo test add_handles_negative -- --nocapture and inspect the log.
  3. Add a # Panics section to the doc comments to describe when the function panics.

Wrap-Up

Tests and doc comments are the first lines of defense for a reliable Rust codebase. cargo test works out of the box, and examples inside /// comments execute as real tests. Next time, we'll run this code safely across multiple threads as we introduce concurrency basics.

💬 댓글

이 글에 대한 의견을 남겨주세요