atoum/praspel-extension
Atoum extension that brings Praspel design-by-contract support to PHP test suites, letting you declare and verify preconditions, postconditions, and invariants alongside atoum assertions. Use annotations to specify expected behavior and catch contract violations early.
First, a reality check. This package was last released in February 2017 and is archived. It targets the atoum 2.x/3.x extension API and PHP 5.6–7.x, and pulls in the abandoned hoa/* stack (hoa/praspel, hoa/realdom, hoa/compiler, hoa/consistency). Budget for a pin-and-freeze integration, not a greenfield one — composer require --dev atoum/praspel-extension:^1 on PHP 8 will either fail dependency resolution or fatal at runtime. If you only need the idea (property-based/contract testing), read the next section and then look at giorgiosironi/eris instead.
Assuming you are on a compatible PHP/atoum pair:
hoa/praspel comes in transitively; do not add it separately at a different version..atoum.php ($runner->addExtension(new atoum\praspel\extension($script));) or, on older atoum releases, by requiring the package's bundled extension.php from your bootstrap. Use whichever shape the package README shows for your atoum version — the two APIs are not interchangeable.vendor/atoum/praspel-extension/src/ and its tests/ directory. The package is tiny: the src tree tells you the exact asserter class name, and therefore the fluent method name you call on $this->assert. The README is the only documentation and it is thin, so the extension's own test suite is the real usage guide.@requires, @ensures, @invariant, @throwable). The atoum extension's job is to hand a class or method name to Hoa\Praspel\Praspel, which parses those annotations with a hoa/compiler grammar, samples the @requires realistic domains to produce inputs, and checks @ensures/@invariant against the results.First use case: pick one small, pure, autoloadable value object. Annotate it:
/**
* @requires x: integer between(2, 1000);
* @ensures \result: integer >= 2;
*/
public function nextPrime($x) { /* ... */ }
Then write a single atoum test that asserts the contract (asserter name per the README / src), run vendor/bin/atoum -f tests/Units/Prime.php, and watch it generate random integers in [2, 1000] rather than the three cases you would have hard-coded. That is the whole value proposition: the contract is the data provider and the oracle.
@dataProvider-style arrays for combinatorial inputs with a @requires clause. between(), among(), contains(), float(), string() and friends live in Hoa\Realdom; the sampler does the work. Reserve explicit atoum assertions for the boundaries you actually care about (0, negative, max) — realistic domains sample, they do not enumerate.or in @requires. Praspel walks alternative preconditions to hit different paths. Writing @requires x: integer between(1,10) or integer between(-10,-1); is the idiomatic way to get both halves of an if exercised, and it is far more readable than two test methods.--tags praspel) and run them on a schedule or pre-merge only. You do not want probabilistic tests in the fast inner loop or as a hard gate on every push.@invariant is the useful part for entities: hydrate fixtures normally, then assert the invariant holds across them. This catches "setter left object in impossible state" bugs that plain getters tests miss.Hoa\Realdom standalone. If the atoum integration fights you, you can call the sampler directly to build fixture arrays without involving atoum assertions at all. That is often the pragmatic 80% win.opcache.save_comments=0 silently kills it. The contract is a comment. Any environment that strips docblocks — some production builds, box phar compaction, aggressive Docker PHP configs — gives you zero clauses and zero checks. Assert that a parsed contract has at least one clause before trusting a green run; a typo'd class name or unparsed annotation otherwise "passes".hoa/compiler. One missing semicolon, an unescaped backslash in a namespaced type, or $this where \result was meant and you get a parser exception far from your test. Validate annotations incrementally — one class at a time.@ensures \result: float between(a, b) with tolerance built into the range rather than ==. Log the sampled inputs in your failure messages or you will be unable to bisect.extension.php for an Atoum\Extension interface, and assertion/asserter plumbing changed. There is no compatible release of this package. Treat an atoum upgrade as a rewrite, not a bump.hoa/* graph is abandoned. hoa/consistency, hoa/protocol and hoa/compiler have known PHP 8 incompatibilities and no maintainer. If you must keep this alive, fork them into a private registry and pin by commit — do not rely on Packagist resolution.Hoa\Realdom predicates, which is the cleanest way to teach it about your own value objects (money, IDs, enums). Custom asserters are added by extending the package's asserter and registering it on the test's assertion manager — the package's own src is the only example.Hoa\Praspel\Praspel exposes the clause objects) whenever an assertion "passes" suspiciously fast. Nine times out of ten the contract was empty and the test was a no-op.How can I help you explore Laravel packages today?