Using the Test Runner

Rather than manually shrinking, proptest’s TestRunner provides this functionality for us and additionally handles things like panics. The method we’re interested in is run. We simply give it the strategy and a function to test inputs and it takes care of the rest.

use proptest::test_runner::{Config, FileFailurePersistence,
                            TestError, TestRunner};

fn some_function(v: i32) {
    // Do a bunch of stuff, but crash if v > 500.
    // We return to normal `assert!` here since `TestRunner` catches
    // panics.
    assert!(v <= 500);
}

// We know the function is broken, so use a purpose-built main function to
// find the breaking point.
fn main() {
    let mut runner = TestRunner::new(Config {
        // Turn failure persistence off for demonstration
        failure_persistence: Some(Box::new(FileFailurePersistence::Off)),
        .. Config::default()
    });
    let result = runner.run(&(0..10000i32), |v| {
        some_function(v);
        Ok(())
    });
    match result {
        Err(TestError::Fail(_, value)) => {
            println!("Found minimal failing case: {}", value);
            assert_eq!(501, value);
        },
        result => panic!("Unexpected result: {:?}", result),
    }
}

That’s a lot better! Still a bit boilerplatey; the proptest! macro will help with that, but it does some other stuff we haven’t covered yet, so for the moment we’ll keep using TestRunner directly.