Testing and Documentation
Write unit tests, integration tests, and generate documentation for your Rust projects.
Writing Doc Tests in Rust
Learn how to write doc tests directly in your code's documentation to provide runnable examples and ensure the examples remain up-to-date.
What are Doc Tests?
Doc tests are runnable examples embedded directly within your code's documentation. Rust's testing framework can execute these examples as part of your regular test suite. This offers a powerful way to verify that your documentation examples are not only correct but also remain synchronized with your actual code behavior. If the code changes, the doc tests will fail, immediately alerting you to the fact that the documentation needs updating.
How to Write Doc Tests
Writing doc tests in Rust is surprisingly simple. You include code examples within specially formatted comments, and the `cargo test` command automatically finds and executes them.
Here's the general syntax:
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
Let's break down this example:
- `/// Adds one to the number given.` : This is a regular documentation comment explaining the function's purpose.
- `/// # Examples` : This section introduces the example. The `#` is crucial; it indicates this is a heading within the documentation.
- `///` followed by a space then ` ``` ` : These backticks delimit a code block. The compiler interprets the content inside as Rust code. The ` ``` ` needs to be on its own line immediately following the previous documentation comment.
- The code within the backticks is a complete, runnable example. It can include `let` declarations, function calls, and assertions. It *must* be valid Rust code.
- ` ``` ` marks the end of the code block. Again, must be on its own line.
Running Doc Tests
To run your doc tests, simply execute the standard Cargo test command:
cargo test
Cargo will automatically discover and run any doc tests embedded in your crate's documentation. The output will indicate whether the tests passed or failed.
Tips and Tricks
- Use `assert_eq!` and `assert!` for verification: These macros allow you to check that the expected results are produced by your code.
- Avoid lengthy examples: Keep your doc tests concise and focused on demonstrating a specific aspect of your code. Long, complicated examples can become difficult to maintain.
- Use qualified paths: In your examples, use qualified paths (e.g., `my_crate::function_name`) to refer to items in your crate. This makes your examples more robust and less dependent on the surrounding context. Without a qualified path, you might need to add `use` statements to your doc test, which complicates things.
- Use `#[cfg(doctest)]` for test-only dependencies: If your doc test requires a dependency that isn't needed for the main crate code, add the dependency to your `Cargo.toml` file with the `doctest` feature enabled. Then, use the `#[cfg(doctest)]` attribute to only include the dependency when running doc tests. This prevents unnecessary dependencies from being included in the main build.
- Handle Errors Properly: If the documented function returns a `Result`, make sure your doc test example handles both the success and error cases, and asserts that the success case works as expected.
Ignoring Parts of Doc Tests
Sometimes you might want to include code in a doc test example that shouldn't be executed by the test runner. This could be code that requires external setup, or code that intentionally panics, or simply setup code that isn't essential to the example. You can use the `#[ignore]` attribute and the `// not_desired: ` prefix to control what the test runner will do.
/// # Examples
///
/// ```
/// // not_desired: let mut f = File::open("foo.txt").unwrap(); // requires file system access
/// let x = 5;
/// assert_eq!(x, 5);
/// ```
/// # Examples
///
/// ```should_panic
/// #[ignore]
/// panic!("This should panic, but it's ignored by the test runner")
/// ```
- `// not_desired: ` - Lines beginning with this prefix in the ``` section are ignored.
- `#[ignore]` - when applied to the whole ``` block, it is a signal to the test runner that the code should not be executed and any failure should be ignored
- ` ```should_panic ` - if you expect a certain portion of the code to panic