Integrated shrinking
generate() returns value + lazy shrink tree together — transformed generators (map, flatMap) shrink correctly for free.
One framework-agnostic engine, two framework adapters — Testo and PHPUnit.
property-testing-core — the framework-agnostic engine: generators, shrinking, the regression corpus, events. Depends on nothing but PHP.property-testing-testo — the #[Property] attribute, self-registering with Testo's interceptor discovery.property-testing-phpunit — a fluent forAll()->check() trait for PHPUnit test cases.Install core plus exactly the adapter your test suite already uses; composer why testo/testo stays empty if you never asked for it.
property-testing-openapi — property-based contract testing for an existing API from its own OpenAPI document: generated valid and negative request cases, an operation suite with no-5xx oracles, and pre-transport validation via openapi-contract. The runner surface works unchanged under Testo and PHPUnit, with the same PROPERTY_RUNS/PROPERTY_SEED/PROPERTY_DB environment.property-testing-names — realistic person-name generators (en/ru, gender-consistent parts) for properties whose inputs are people.Property falsified after 246 successful run(s); seed=7382910
Original: maxAttempts=17, baseSeconds=91, cap=847, attempts=23
Shrunk: maxAttempts=1, baseSeconds=848, cap=847, attempts=1 (12 shrink step(s), 41 trial(s))
Changed: maxAttempts=17 -> 1, baseSeconds=91 -> 848, attempts=23 -> 1Four generated arguments went in; the Changed: line tells you only three of them actually drive the failure — the shrinker found that by searching, you didn't have to step through a debugger to see it.
See Cookbook for real monorepo incidents property tests would have caught before they shipped.