GitHub - shrynx/protest: An ergonomic, powerful, and feature-rich property
⚓ Rust 📅 2025-11-01 👤 surdeus 👁️ 12I wrote a library for property based testing in rust. I'll post part of the readme here for ease
Property-Based Testing for Rust - An ergonomic, powerful, and feature-rich property testing library with minimal boilerplate.
Features
Ergonomic API - Test properties with closures, no boilerplate
Automatic Generator Inference - Smart type-based generator selection
Derive Macros - #[derive(Generator)]for custom types
Declarative Macros - property!,assert_property!,generator!
Async Support - First-class async property testing
Smart Shrinking - Automatic minimal counterexample finding
Failure Persistence - Save and replay failing test cases (optional)
CLI Tool - Manage failures from the command line (protest-cli)
Fluent Builders - Chain configuration methods naturally
Common Patterns - Built-in helpers for mathematical properties
Parallel Execution - Run tests in parallel for speed
Statistics & Coverage - Track generation and test coverage
Flexible - Works with any type, sync or async
Ultra-Simple Example
use protest::*;
#[test]
fn test_addition_commutative() {
// Test that addition is commutative with just one line!
property!(generator!(i32, -100, 100), |(a, b)| a + b == b + a);
}
Ergonomic API Example
use protest::ergonomic::*;
#[test]
fn test_reverse_twice_is_identity() {
property(|mut v: Vec<i32>| {
let original = v.clone();
v.reverse();
v.reverse();
v == original
})
.iterations(1000)
.run_with(VecGenerator::new(IntGenerator::new(-50, 50), 0, 100))
.expect("Property should hold");
}
Attribute Macro Example
use protest::property_test;
#[property_test(iterations = 100)]
fn test_string_length(s: String) {
// Generator automatically inferred from type
assert!(s.len() >= 0);
}
Custom Struct Example
use protest::Generator;
#[derive(Debug, Clone, PartialEq, Generator)]
struct User {
#[generator(range = "1..1000")]
id: u32,
#[generator(length = "5..50")]
name: String,
age: u8,
active: bool,
}
#[property_test]
fn test_user_id(user: User) {
assert!(user.id > 0 && user.id < 1000);
}
1 post - 1 participant
🏷️ Rust_feed