Testing in Rust
// Unit tests: in the same file as the code
fn add(a: i32, b: i32) -> i32 { a + b }
fn divide(a: f64, b: f64) -> Option {
if b == 0.0 { None } else { Some(a / b) }
}
#[cfg(test)] // Only compiled when running tests
mod tests {
use super::*; // Import everything from parent module
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
assert_eq!(add(-1, 1), 0);
assert_ne!(add(2, 2), 5);
}
#[test]
fn test_divide() {
assert_eq!(divide(10.0, 2.0), Some(5.0));
assert_eq!(divide(10.0, 0.0), None);
}
#[test]
#[should_panic(expected = "overflow")]
fn test_overflow() {
let _ = i32::MAX.checked_add(1).expect("overflow");
}
#[test]
fn test_with_result() -> Result<(), String> {
let x: i32 = "5".parse().map_err(|e: std::num::ParseIntError| e.to_string())?;
assert_eq!(x, 5);
Ok(())
}
}
// Integration tests: in tests/ directory
// tests/integration_test.rs:
// use my_crate::add;
// #[test]
// fn test_add_integration() { assert_eq!(add(1, 2), 3); }
// Running tests:
// cargo test - all tests
// cargo test test_add - matching name
// cargo test -- --nocapture - show println! output
// cargo test -- --ignored - run #[ignore]d tests Property Testing and Benchmarks
// Property-based testing with proptest:
// proptest = "1"
use proptest::prelude::*;
proptest! {
#[test]
fn test_reverse_reverse(s: String) {
let reversed: String = s.chars().rev().collect();
let double_reversed: String = reversed.chars().rev().collect();
prop_assert_eq!(s, double_reversed);
}
#[test]
fn test_sort_idempotent(mut v: Vec) {
v.sort();
let first_sort = v.clone();
v.sort();
prop_assert_eq!(first_sort, v);
}
}
// Benchmarks (nightly or with criterion):
// criterion = "0.5"
// use criterion::{criterion_group, criterion_main, Criterion};
// fn benchmark_add(c: &mut Criterion) {
// c.bench_function("add", |b| b.iter(|| add(2, 3)));
// } 🎯 Practice
- Write unit tests for a Vec-based Stack: test push, pop, peek with empty and non-empty stacks
- Write an integration test for a function in your library crate
- Use #[should_panic] to test that your divide function panics appropriately
- Add proptest for a string function: verify it never panics on arbitrary input
🎉 Key Takeaways
- Unit tests go in the same file inside #[cfg(test)] mod tests
- Integration tests go in tests/ directory - test public API only
- assert_eq!, assert_ne!, assert!, panic with descriptive messages
- #[should_panic] tests that code panics; #[ignore] skips slow tests