Testing Basics
10 examples to get you started with Testing - 7 basic and 3 intermediate.
Search across all documentation pages
10 examples to get you started with Testing - 7 basic and 3 intermediate.
cargo test from Cargo BasicsTests are functions annotated with #[test] in the same module or a tests/ module.
fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn adds_positive() {
assert_eq!(add(2, 2), 4);
}
}#[cfg(test)] compiles tests only for cargo testassert_eq! prints left/right on failurecargo test adds_positive filters by nameRelated: Unit vs Integration Tests - test placement
Rust provides macros for boolean and equality checks.
#[test]
fn validates_email() {
let email = "user@example.com";
assert!(email.contains('@'));
assert_ne!(email, "");
assert_eq!(email.split('@').count(), 2);
}assert! fails on false conditionsassert_eq! uses PartialEq and shows diffassert!(x > 0, "x was {x}")Verify code panics on invalid input.
#[test]
#[should_panic(expected = "divide by zero")]
fn panics_on_zero() {
let _ = 1 / 0;
}Result in library codeexpected substring must match panic payload#[should_panic] without expected matches any panicReturn Result from tests to use ? for setup failures.
#[test]
fn reads_config() -> std::io::Result<()> {
let data = std::fs::read_to_string("Cargo.toml")?;
assert!(data.contains("[package]"));
Ok(())
}Err fails the test like assert!unwrap in setup? on parsing and I/O helpersassert! for behavioral expectationsCargo filters tests by name substring.
cargo test
cargo test add_
cargo test --lib
cargo test --test integration_orders--lib runs only unit tests in src/--test NAME runs one integration test file-- --nocapture shows println! output-- --test-threads=1 for tests sharing global stateTest private functions from the same crate.
mod parser {
fn parse_id(s: &str) -> Option<u64> {
s.parse().ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_digits() {
assert_eq!(parse_id("42"), Some(42));
}
}
}mod tests beside codeuse super::* imports private itemspub APISkip slow tests by default; run explicitly in CI nightly.
#[test]
fn fast_case() {
assert_eq!(2 + 2, 4);
}
#[test]
#[ignore]
fn heavy_simulation() {
// long-running
}cargo test -- --ignored#[ignore] excludes test from default cargo testLibraries can customize test discovery (advanced).
// src/lib.rs
pub fn init() {}
#[cfg(test)]
mod tests {
#[test]
fn smoke() {
super::init();
}
}test crate attributes only when requiredRelated: Test Organization - shared setup
Add test-only crates without shipping them to consumers.
[dev-dependencies]
tempfile = "3"
pretty_assertions = "1"#[test]
fn writes_temp_file() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("out.txt");
std::fs::write(&path, b"ok").unwrap();
assert!(path.exists());
}dev-dependencies are not transitivepretty_assertions::assert_eq for clearer diffstempfile avoids polluting repo with test artifactsRelated: Mocking & Test Doubles - fakes and mocks
Combine unit tests with stronger guarantees.
#[test]
fn reverse_twice_is_identity() {
let v = vec![1, 2, 3];
let mut w = v.clone();
w.reverse();
w.reverse();
assert_eq!(v, w);
}#[tokio::test] (Testing Async Code)Related: Testing Best Practices - team standards
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Reviewed by Chris St. John·Last updated Jul 16, 2026