Lesson Details

Testing

Cargo includes a subcommand for running tests, and Rust provides support for authoring tests through the test attribute macro.

If you initialize a new library crate with cargo new, it will come with unit tests, but Rust also supports integration and documentation tests natively.

cargo new --lib testing_ground

The lib.rs includes a function called add that is tested in a module that only compiles if we’re running tests. The whole module is gated based on whether test is set or not, which is something Cargo will do for us when running cargo test.

Tests in Rust are regular function. If they return a Result::Err or panic, the test fails. Since tests are regular functions, we can identify our test functions with the test attribute macro.

pub fn add(left: u64, right: u64) -> u64 {
left + right
}

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

#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

Running cargo test produces pass/fail output.

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Doc-tests testing_ground

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

More approaches to testing are supported by the crates.io ecosystem, including snapshot testing, table-based testing, property-based testing, mutation testing, fuzz testing, and more.

Documentation

Rust comes with documentation tools built-in. Running cargo doc on the libary we just initialized produces the documentation that was written for all items as a webpage.

cargo doc --open

By default this doesn’t include a whole lot of content, but you can turn on a lint to warn when documentation isn’t written for an item.

In our recent testing_ground crate, open Cargo.toml and add a rust lint that warns when compiling if documentation isn’t written for items.

[package]
name = "testing_ground"
version = "0.1.0"
edition = "2024"

[dependencies]

[lints.rust]
missing_docs = "warn"

Then when running cargo test, cargo doc, or similar commands, missing documentation will generate a warning.

❯ cargo test
Compiling testing_ground v0.1.0 (/rust-adventure/testing_ground)
warning: missing documentation for the crate
--> src/lib.rs:1:1
|
1 | / pub fn add(left: u64, right: u64) -> u64 {
2 | | left + right
... |
14 | | }
| |_^
|
= note: requested on the command line with `-W missing-docs`

warning: missing documentation for a function
--> src/lib.rs:1:1
|
1 | pub fn add(left: u64, right: u64) -> u64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: `testing_ground` (lib) generated 2 warnings
warning: `testing_ground` (lib test) generated 2 warnings (2 duplicates)
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.15s
Running unittests src/lib.rs (target/debug/deps/testing_ground-a4285d5bace8f285)

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Doc-tests testing_ground

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

This shows warnings for missing documentation for the crate itself as well as the add function.

We can add documentation using //! for the crate and /// for items like the function. Content is written using markdown syntax. Here we’ve also included an example in the documentation, which gets compiled and included in the tests that run, ensuring that our documentation is never out of date.

//! This is crate level documentation

/// This is documentation about `add`.
///
/// ```rust
/// use testing_ground::add;
///
/// assert_eq!(add(2,2), 4);
/// ```
pub fn add(left: u64, right: u64) -> u64 {
left + right
}

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

#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

Examples

Finally, Rust includes support for examples. In a new file in examples/adds.rs write a new program that uses the testing_ground library to power a binary program.

//! This example shows how to use the add function
//! in the context of a standalone application.
use testing_ground::add;

fn main() {
let number = add(2, 2);

assert_eq!(number, 4);
}

This example can now be run with the --example flag. The example is named after the filename by default.

cargo run --example adds

The examples directory is a very common feature in Rust projects, because it can show real-world usage of libraries.