RUST / CHAPTER 12
Tests for boundaries and mutation contracts
AdvancedDerive tests from a function’s promises and failure modes.
By the end of this chapter
- Cover empty and duplicate cases
- Assert Result variants deliberately
- Check input preservation separately from outputs
The idea
A unit test should make a contract observable. assert_eq compares an actual result with an independently derived expected value, while pattern matching can check a Result or Option variant. A test for invalid input should establish that failure is reported in the promised form rather than merely confirming that some panic occurred. Small named cases explain which behavior a regression would break.
Boundary cases reveal assumptions hidden by ordinary examples. Empty input tests initialization, all-negative values test maximum selection, and repeated values test duplicate handling and tie policy. For functions that borrow immutably, the type system already prevents ordinary mutation through that borrow, but returned owned collections may still need tests for order and completeness. State numerical bounds when integer overflow is outside the supported contract.
fn first_index(xs:&[i32],target:i32)->Option<usize>{xs.iter().position(|&x|x==target)}
fn main(){assert_eq!(first_index(&[4,2,4],4),Some(0));assert_eq!(first_index(&[],4),None);println!("checks passed");}checks passed
The duplicate case tests first occurrence, while empty input tests the absent result.
Try it yourself
Write cases for a stable filter that must preserve duplicates and input order.
Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.
CHECK YOUR UNDERSTANDING