What it is
proptest is a property-based testing library that generates random inputs to falsify stated properties, then shrinks any failure to a minimal case.
State a property that should hold for all inputs. proptest generates hundreds of cases, and on failure shrinks the input to the smallest reproduction.
Installation
cargo add --dev proptestGetting started
The smallest useful thing you can do with it, and what each part means.
use proptest::prelude::*;
proptest! {
#[test]
fn serialise_round_trips(book in any::<Book>()) {
let encoded = serde_json::to_string(&book)?;
let decoded: Book = serde_json::from_str(&encoded)?;
prop_assert_eq!(book, decoded);
}
#[test]
fn slugify_is_url_safe(s in ".*") {
let slug = slugify(&s);
prop_assert!(slug.chars().all(|c| c.is_ascii_alphanumeric() || c == '-'));
}
}Advanced usage
Where the library earns its place over a simpler alternative.
// Generate only inputs that satisfy your domain's rules.
fn valid_book() -> impl Strategy<Value = Book> {
(
"[a-zA-Z ]{1,200}",
1400u16..=2100,
prop::collection::vec("[a-z]{1,10}", 0..5),
).prop_map(|(title, year, tags)| Book { title, year, tags })
}
proptest! {
#![proptest_config(ProptestConfig { cases: 500, ..Default::default() })]
#[test]
fn accepts_all_valid_books(book in valid_book()) {
prop_assert!(validate(&book).is_ok());
}
}Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Local file too many rejects
- prop_assume is discarding most generated inputs. Write a strategy that only produces valid values.
- A failure will not reproduce
- Use the seed printed in the failure output, and keep the proptest-regressions file in version control.
Best practices
- Start with round-trip and invariant properties — they find the most bugs per line written.
- Write custom strategies rather than filtering with prop_assume, which discards cases and slows generation.
- Commit the proptest-regressions files; they pin previously-found failures as permanent tests.
- Use property tests alongside example tests, not instead of them.
Background
Why it exists, and what it was reacting to.
Modelled on Haskell's QuickCheck and Python's Hypothesis, proptest finds the edge cases example-based tests miss — and its shrinking turns a 400-element counterexample into the two-element one that actually matters.
