π§ͺ Rust Test Organization: Building Your Quality Control Factory
The Story: Your Code Factory Needs Inspectors!
Imagine youβre running a toy factory. You make toys, but before shipping them to kids, you need to check they work properly!
- Unit tests = Checking each part (like testing if a wheel spins)
- Integration tests = Checking the whole toy works together (like testing if the car actually drives)
Rust gives you a super organized system to run all these checks. Letβs explore it!
π Integration Tests: Testing the Whole Factory
What Are Integration Tests?
Unit tests check tiny pieces inside your code. But integration tests check if everything works together from the outside.
Think of it like this:
- Unit test = Testing if the engine starts β
- Integration test = Testing if the whole car drives β
Integration tests treat your code like a stranger would - they only use whatβs publicly available.
Why Separate Them?
Because integration tests are special:
- They live outside your
srcfolder - Each file becomes its own separate test program
- They can only use your public functions
π The tests Directory: Where Big Tests Live
Setting Up Your Test Folder
my_project/
βββ Cargo.toml
βββ src/
β βββ lib.rs π Your library code
βββ tests/ π Integration tests live here!
βββ test_math.rs
βββ test_strings.rs
Your First Integration Test
Create a file tests/integration_test.rs:
use my_project; // Import your crate
#[test]
fn it_adds_two() {
assert_eq!(my_project::add(2, 2), 4);
}
Key Points:
- Each file in
tests/is a separate crate - You must
useyour library like any external user would - Run with:
cargo test
Organizing Helper Code
What if tests need to share helper functions?
tests/
βββ common/
β βββ mod.rs π Shared helpers here
βββ test_add.rs
βββ test_multiply.rs
In tests/common/mod.rs:
pub fn setup() {
// Shared setup code
}
In your test file:
mod common;
#[test]
fn test_with_setup() {
common::setup();
// Your test code
}
Why a subfolder? Files directly in tests/ become test crates. Files in subfolders donβt!
π Documentation Tests: Teaching and Testing Together!
The Magic of Doc Tests
Rust has a superpower: code examples in your documentation actually run as tests!
/// Adds two numbers together.
///
/// # Examples
///
/// ```
/// let result = my_crate::add(2, 3);
/// assert_eq!(result, 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
When you run cargo test, Rust:
- Finds code blocks in your docs
- Runs them as tests
- Makes sure your examples actually work!
Why Doc Tests Are Brilliant
| Problem Without Doc Tests | Solution With Doc Tests |
|---|---|
| Examples get outdated | They fail if broken! |
| Nobody trusts the docs | Examples are verified |
| Extra work to maintain | Tests = Documentation |
Hiding Setup Code
Sometimes you need extra code, but donβt want to show it:
/// Returns a greeting.
///
/// ```
/// # use my_crate::greet; // Hidden line!
/// let msg = greet("World");
/// assert_eq!(msg, "Hello, World!");
/// ```
pub fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
Lines starting with # run but donβt appear in docs!
ποΈ Test Organization: The Master Plan
Where Tests Live
graph TD A["Your Rust Project"] --> B["Unit Tests"] A --> C["Integration Tests"] A --> D["Doc Tests"] B --> E["Inside src/ files"] B --> F["#[cfg#40;test#41;] modules"] C --> G["tests/ directory"] C --> H["Each file = separate crate"] D --> I["In /// comments"] D --> J["Code blocks run as tests"]
The Three Test Types
| Type | Location | Purpose |
|---|---|---|
| Unit | src/*.rs |
Test private internals |
| Integration | tests/*.rs |
Test public API |
| Doc | /// comments |
Verify examples work |
Unit Test Module Pattern
// In src/lib.rs or any src file
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(1, 1), 2);
}
}
The #[cfg(test)] means this code only compiles during testing - not in your final program!
π Ignoring Tests: βNot Today, Test!β
When to Ignore
Sometimes tests:
- Take too long β°
- Need special setup π§
- Are temporarily broken π οΈ
The #[ignore] Attribute
#[test]
fn quick_test() {
assert!(true); // Runs normally
}
#[test]
#[ignore]
fn slow_test() {
// Takes 10 minutes - skip by default!
std::thread::sleep(
std::time::Duration::from_secs(600)
);
}
Running Ignored Tests
# Run only ignored tests
cargo test -- --ignored
# Run ALL tests (including ignored)
cargo test -- --include-ignored
Adding a Reason
#[test]
#[ignore = "requires database connection"]
fn test_database() {
// Only run when DB is available
}
π― Running Specific Tests: Laser Focus!
Run Tests by Name
# Run tests containing "add"
cargo test add
# Run exact test name
cargo test test_addition
# Run tests in specific module
cargo test math::
Examples in Action
#[test]
fn test_addition() { }
#[test]
fn test_addition_negative() { }
#[test]
fn test_subtraction() { }
cargo test addition
# Runs: test_addition, test_addition_negative
# Skips: test_subtraction
Filter by Test Location
# Only unit tests
cargo test --lib
# Only integration tests
cargo test --test integration_test
# Only doc tests
cargo test --doc
Show All Output
# See println! output even for passing tests
cargo test -- --show-output
# Run tests one at a time (not parallel)
cargo test -- --test-threads=1
π Your Complete Testing Toolkit
graph TD A["cargo test"] --> B{What to run?} B --> C["Everything"] B --> D["--lib: Unit tests only"] B --> E["--doc: Doc tests only"] B --> F["--test NAME: Specific integration test"] B --> G["FILTER: Tests matching pattern"] C --> H{Options} H --> I["--ignored: Only ignored"] H --> J["--include-ignored: All"] H --> K["--show-output: See prints"] H --> L["--test-threads=1: Sequential"]
π Quick Reference
| Command | What It Does |
|---|---|
cargo test |
Run all tests |
cargo test NAME |
Run tests matching NAME |
cargo test --lib |
Only unit tests |
cargo test --doc |
Only doc tests |
cargo test --test FILE |
Specific integration test |
cargo test -- --ignored |
Only ignored tests |
cargo test -- --show-output |
Show all output |
π― Remember This!
- Integration tests = External tests in
tests/folder - Doc tests = Code in comments that actually runs
#[ignore]= Skip slow/special tests by default- Filter tests = Use
cargo test NAMEto run specific ones - Shared helpers = Put in
tests/common/mod.rs
You now have the complete testing toolkit for Rust! Your code factory has professional-grade quality control. Go build amazing things with confidence! π¦β¨
