Unit Tests with #[test]
The late-fee rule changed: 10 per day, but never more than 200. You edit one line. Did you break the zero-days case? Rust has testing built into the language and into Cargo, so checking takes one command and no extra setup.
The rule
Tests sit beside the code; a test passes unless it panics.
// src/fees.rs
pub fn late_fee(days_late: u32) -> u32 {
(days_late * 10).min(200)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn charges_ten_per_day() {
assert_eq!(late_fee(3), 30);
}
#[test]
fn nothing_when_on_time() {
assert_eq!(late_fee(0), 0);
}
#[test]
fn capped_at_two_hundred() {
assert_eq!(late_fee(50), 200);
}
}#[cfg(test)]compiles the module only forcargo test, so it adds nothing to real builds.use super::*;brings the parent module's items in. Becausetestsis a child module, it can test private functions too.#[test]marks a function as a test. It passes if it returns normally and fails if it panics.
The assert macros panic with a helpful message when a check fails:
assert!(cond): the condition must be true.assert_eq!(left, right)andassert_ne!(left, right): on failure they print both values.
Expected panics and Result. Suppose lend panics with the message "already on loan" when a book is already out:
#[test]
#[should_panic(expected = "already on loan")]
fn cannot_lend_twice() {
let mut book = Book::new("Iron Tides", 380);
book.lend();
book.lend();
}
#[test]
fn parses_card() -> Result<(), std::num::ParseIntError> {
assert_eq!("1042".parse::<u32>()?, 1042);
Ok(())
}Running them: cargo test runs every test (in parallel). cargo test capped runs only tests whose names contain "capped". Output printed by passing tests is hidden unless you add -- --nocapture.
The shortcut
For every function, write three tests: the ordinary case, the edge, and the limit.
Ordinary
3 days late → 30.
assert_eq!(late_fee(3), 30);
The trap is a test with no assertion. It calls the function and passes as long as nothing panics, which proves almost nothing.
Drills
Answer fast — trust the rule.
When does a #[test] function fail?
What does #[cfg(test)] on the tests module do?
Can a unit test in mod tests call a private function from the same file?
Which command runs only tests with "capped" in their name?
Remember
- Unit tests go in
#[cfg(test)] mod testsbeside the code; a test passes unless it panics. - Test the ordinary case, the edge and the limit, with
assert_eq!for clear failures. - Trap: a test with no assertion proves nothing.
