Documentation Tests
Documentation tests (or doc-tests) are fenced Rust code blocks written inside /// or //! documentation comments that cargo test (via rustdoc --test) automatically extracts, compiles, and executes as standalone test binaries. Because every documented example is tested on every cargo test run, API examples in Rust documentation never drift out of sync with the actual code.
In `src/lib.rs`:
/// ```
/// use my_crate::add;
/// assert_eq!(add(2, 3), 5);
/// ```
|
v (`rustdoc --test` wraps block in `fn main() { ... }`)
Compiles against `my_crate` as an external caller & runs assertions!
Writing a Documentation Test
When rustdoc encounters a code block inside a doc comment without a fn main() declaration, it automatically wraps the snippet inside fn main() { ... } and compiles it as an external crate linking against your library.
Note that Cargo only runs doc-tests on library targets (src/lib.rs and its modules)—doc comments in binary-only targets (src/main.rs) are not executed by cargo test --doc.
/// Divides `dividend` by `divisor`, returning `None` if `divisor` is zero.
///
/// # Examples
///
/// ```
/// use my_math::checked_div;
///
/// assert_eq!(checked_div(10, 2), Some(5));
/// assert_eq!(checked_div(10, 0), None);
/// ```
pub fn checked_div(dividend: i64, divisor: i64) -> Option<i64> {
if divisor == 0 {
None
} else {
Some(dividend / divisor)
}
}
fn main() {
println!("10 / 2 = {:?}", checked_div(10, 2));
}
10 / 2 = Some(5)
Running cargo test --doc executes the extracted example:
Doc-tests my_math
running 1 test
test src/lib.rs - checked_div (line 5) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s
Hiding Setup Lines with # and Using ? in Doc-Tests
In a doc-test, any line starting with # (a hash followed by a space) is compiled and executed when the test runs, but hidden from the rendered HTML documentation generated by cargo doc. This lets you hide repetitive boilerplate, imports, or a Result-returning fn main() wrapper so readers can use ? directly in the visible snippet:
/// Parses a port number from a string slice.
///
/// ```
/// # use std::num::ParseIntError;
/// # fn main() -> Result<(), ParseIntError> {
/// let port: u16 = "8080".parse()?;
/// assert_eq!(port, 8080);
/// # Ok(())
/// # }
/// ```
pub fn default_port() -> u16 {
8080
}
fn main() {
println!("Default port: {}", default_port());
}
Default port: 8080
Doc-Test Code Block Attributes
| Code Block Fence | cargo test --doc Behavior |
Use Case |
|---|---|---|
``` or ```rust |
Compiles and runs; must exit without panicking. | Standard runnable API examples. |
```should_panic |
Compiles and runs; passes only if it panics. | Documenting precondition panics (assert!, out-of-bounds). |
```no_run |
Compiles (verifying types and syntax), but does not execute at runtime. | Examples that start infinite network servers, perform disk I/O, or call external services. |
```compile_fail |
Passes only if compilation fails. | Demonstrating borrow-checker or type-safety guarantees that reject invalid code. |
```ignore |
Neither compiled nor executed by rustdoc. |
Incomplete pseudocode (avoid when no_run can be used). |
```text / ```toml |
Treated as non-Rust text; skipped by rustdoc --test. |
Program output, CLI commands, or configuration snippets. |