Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Praspel Extension Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

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:

  1. Install the extension as a dev dependency. hoa/praspel comes in transitively; do not add it separately at a different version.
  2. Register it with the runner in .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.
  3. Look first at 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.
  4. Understand what it does, not what it asserts. Praspel is a design-by-contract language living in docblock annotations (@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.

Implementation Patterns

  • Contract as data provider. Replace hand-written @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.
  • Branch coverage through 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.
  • Keep the SUT pure. Sampling can only construct inputs and inspect return values/exceptions. Anything needing a database, clock, HTTP client, or filesystem has to be stubbed with atoum's mock system around the Praspel-driven call — Praspel does not know about mocks, and mixing the two in one assertion makes failures unreadable.
  • Split the run. Put contract tests in their own directory or atoum tag (--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.
  • Layer with classic atoum. The best workflow is: one contract assertion per method (broad coverage, catches unexpected inputs) plus a handful of explicit example-based tests (pinpoints failures, documents intent). When a contract test fails, reproduce by reading the sampled value from the failure message and then write a deterministic example test for it.
  • Fixtures and invariants. @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.
  • Use 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.

Gotchas and Tips

  • 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".
  • Grammar parsing is slow and strict. Every annotated class is parsed from scratch by 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.
  • Nondeterminism is real. No supported seeding API, so failures are not reproducible run-to-run. Float postconditions are especially flaky; write @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.
  • The extension API moved. atoum 4 swapped closure-based 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.
  • The 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.
  • Extension points are limited but present. Custom domains come from implementing 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.
  • Debugging aid: dump the parsed contract (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.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource