Download the PHP package rasuvaeff/property-testing-testo without Composer

On this page you can find all versions of the php package rasuvaeff/property-testing-testo. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package property-testing-testo

rasuvaeff/property-testing-testo

Latest Stable Version Total Downloads Build Static analysis Psalm level PHP

Русская версия

Testo adapter for the property-testing engine: the #[Property] attribute, reflection conventions, and environment overrides — a drop-in replacement for the frozen rasuvaeff/property-testing 2.x. Generate hundreds of random inputs per test, find the failing one, and shrink it to a minimal counterexample you can actually read.

Using an AI coding assistant? llms.txt contains a compact API reference you can share with the model.

Part of the property-testing family

Package Use it when
rasuvaeff/property-testing-core You drive the engine yourself: a custom harness, CI guard, CLI checker, or another framework adapter
rasuvaeff/property-testing-testo (this package) You test with Testo — the classic #[Property] attribute
rasuvaeff/property-testing-phpunit You test with PHPUnit — a PropertyTesting trait with a fluent forAll()->check() API

Migrating from rasuvaeff/property-testing 2.x

The frozen rasuvaeff/property-testing package is superseded by this adapter. Migration is one Composer command — your PHP code does not change:

Everything is preserved:

The engine now lives in rasuvaeff/property-testing-core (pulled in automatically), which conflicts with the old package — Composer will refuse a mixed installation rather than let two copies of the namespace collide.

Requirements

Installation

No plugin registration is needed: the #[Property] attribute self-registers with Testo through the framework's interceptor discovery.

Usage

Mark a test method with #[Property] and point it at a generators method that maps each parameter name to a Gen factory. The runner generates random arguments, runs the property runs times, and on the first failure shrinks the counterexample to a minimal one.

On failure, the counterexample is rendered into the test output:

Reproduce the exact run by passing the reported seed back to the attribute: #[Property(runs: 500, seed: 7382910)]. The message also ends with a Path: line — the shrink steps that were accepted — and passing that back beside the seed (#[Property(seed: 7382910, path: 'attempts:1/attempts:3')], or PROPERTY_SEED=… PROPERTY_PATH=…) follows the descent instead of searching for it again. The excerpt above is trimmed; a real run prints Failure: and Path: too.

Conventions

PHP attribute arguments must be constant expressions, so generators cannot be passed inline. Name a method returning array<string, ArbitraryInterface> keyed by parameter name; when the generators argument is omitted the adapter falls back to <testMethod>Generators. The same pattern applies to fixed examples: <testMethod>Examples (or #[Property(examples: 'method')]) returns positional argument tuples that run before the random inputs and are never shrunk.

Declare generators and examples methods public static (public if the body needs $this): their only call site is this adapter's reflection, so Rector's dead-code set would delete private ones.

What the adapter does and does not combine with:

Callable providers

generators and examples also accept a callable. Strings are resolved as a method on the property test class first; only when no such method exists are they treated as external callable names. Non-string callables are stored and invoked when the property is resolved, so an invokable provider can be written directly in a PHP 8.3 attribute:

Reusable static providers can use either [Provider::class, 'method'] or 'Provider::method'. PHP 8.5 additionally allows an inline static function (): array { ... } or a first-class callable such as Provider::method(...) in the attribute. A method on the test class named like a global function (for example range) still wins over that global function.

The flip side of string resolution: a misspelled method name that happens to match a global function ('count', 'range') is invoked as that function — typically failing with its own ArgumentCountError from the zero-argument call, or, when the function takes no arguments, with the result validation rejecting its return. A typo matching nothing fails immediately with neither a method on … nor a callable.

Auto-derived generators (auto: true)

When the parameters are fully described by their types, the provider method can go away entirely: auto: true derives a generator for every parameter from the property's own signature via Gen::forParameters() — the @param psalm type when there is one (int<1, 300>, non-empty-string, list<T>, 'a'|'b'), the native type otherwise:

The provider — explicit or the <testMethod>Generators convention — becomes the overrides and may be partial: the parameters it names are taken as given, the rest are derived. That is the escape hatch for domains no psalm type can express (a float range, a dependent pair built with Gen::flatMap()):

Rules worth knowing:

Attribute parameters

Parameter Meaning
runs Successful checks to complete (default 100). Discarded runs do not count
seed Pins the random phase for reproduction. Also disables corpus replay for this property — the pinned run wins
generators Method name or callable(): array<string, ArbitraryInterface>; default <testMethod>Generators
examples Method name or callable(): iterable<array<mixed>>; default <testMethod>Examples
maxShrinks Cap on accepted shrink steps; 0 disables shrinking
maxDiscards Cap for the discard budget and the skip budget. Left unset the two differ: runs * 10 for discards, runs for environmental skips
timeoutMs Wall-clock deadline for a single run — exceeding it fails the property with DeadlineExceededException
budgetMs Wall-clock budget for the whole random phase — running out fails with TimeBudgetExceededException
shrink ShrinkMode::Full (default), Off (report the input as generated) or Bounded with a budget
shrinkBudgetMs Wall-clock budget for the descent — the one knob that costs determinism, since how far it gets depends on how long the body takes
phases Stages to perform (Phase::Examples, Corpus, Random, Shrink); a subset trades coverage for time on purpose
derandomize Derives an unset seed from the property id instead of drawing one; an attribute seed still wins
path Replays a recorded shrink descent (CounterExample::$path) instead of searching for it; requires seed
edgeCases EdgeCases::None turns off the numeric boundary bias — for a property the edges only cost runs
auto Derives generators from the property's signature for every parameter the provider does not cover; the provider becomes partial overrides. Off by default, and stays off

Environment overrides

One rule decides who wins: the environment dials the suite, the attribute pins the property. PROPERTY_RUNS, PROPERTY_PHASES and PROPERTY_DERANDOMIZE are CI knobs and override the attribute; PROPERTY_SEED and PROPERTY_PATH replay one specific failure and yield to what the attribute wrote down.

Variable Effect
PROPERTY_RUNS Positive integer that overrides every property's run count (dial runs up in CI)
PROPERTY_SEED Integer seed for any property whose attribute omits seed (replay a whole suite). An explicit attribute seed still wins
PROPERTY_VERBOSE Any value except ''/'0' logs every run's generated arguments and each accepted shrink step
PROPERTY_DB Directory path enabling the regression corpus, or a redis://host[:port][/db][?prefix=key-prefix] DSN (rediss:// for TLS) for a corpus shared between CI and developers. Unset means off, nothing is written
PROPERTY_PHASES Comma-separated stage list (examples,corpus,random,shrink, case-insensitive) that overrides the attribute — an unknown name throws rather than skipping a stage. examples,corpus is the fast pull-request gate
PROPERTY_DERANDOMIZE Any value except ''/'0' derives every unset seed from the property id, making a whole suite reproducible without editing it
PROPERTY_PATH A recorded shrink descent replayed instead of searched for. Requires a pinned seed — PROPERTY_SEED or the attribute's — and is refused without one, because an unseeded property gets a random seed and the path would replay a run that never happened. An attribute path wins. It describes one failure, so run it with a filter on that one test — every other property would report the path as stale
PROPERTY_EDGE_CASES mixin or none (case-insensitive) — the numeric boundary bias for the whole suite, overriding the attribute. An unknown value throws

Regression corpus

PROPERTY_DB takes either a directory or a Redis DSN:

The DSN has the shape everything else gives it (the IANA registration, predis, Symfony): the path is the database index, the key prefix is the prefix query parameter, rediss:// is TLS. The pre-0.7 form with the prefix in the path (redis://host/suite-a:) is refused with the new spelling in the message. The value is parsed by the engine's CorpusFactory, shared with the PHPUnit adapter.

A directory remembers a counterexample for whoever owns it — in CI, a machine deleted when the job ends. The Redis form is the same corpus, in the same document, shared: a failure found on a laptop replays in CI and one found in CI replays on the next laptop. It needs ext-redis or predis/predis; neither installed is an error rather than a silent fall back to the filesystem, because a suite told to share its corpus and quietly writing where nobody reads is worse than one that stops. A PROPERTY_DB with any other scheme — a Rediss:// typo, another backend — is likewise an error, never a directory named after the scheme. Credentials in the DSN (redis://user:pass@host) are rejected rather than silently dropped; configure Redis AUTH out of band.

How entries are recorded

Set PROPERTY_DB to a directory and every falsified property records its failure there. On the next run the recorded failures are replayed first (unless the attribute pins its own seed): one that still fails is reported immediately — as a RegressionViolationException for a stored-values entry — and one that no longer fails is pruned. The storage format is exactly the one rasuvaeff/property-testing 2.8 wrote, so existing CI corpora keep working after the migration. Storage details live in the core documentation.

Coverage attributes

The adapter aggregates the per-run TestResult attributes of every executed body — Testo codecov's CoverageResult among them — onto the single TestResult a property test reports. Property tests therefore appear in per-test coverage, and Infection runs them against mutants like any other test.

Stateful / model-based testing

The engine's state machine works unchanged under #[Property]:

See examples/state_machine.php for the full runnable stack example.

Generators

The full generator catalog (Gen::int() … Gen::subset(), Gen::regex(), Gen::commands(), Gen::draw(), writing your own ArbitraryInterface) is the engine's API and is documented in the core README. Everything there is usable from a #[Property] test as-is.

Public API of this package

Type Role
Rasuvaeff\PropertyTesting\Property The attribute — the same FQCN 2.x shipped
Rasuvaeff\PropertyTesting\Testo\PropertyInterceptor Testo interceptor: resolves reflection conventions and environment into a core PropertyDefinition, maps the structured result to one TestResult

TestoTrialExecutor and VerboseListener are @internal: the interceptor's implementation, not a contract. The environment variables and the PROPERTY_DB DSN are parsed by the engine (EnvironmentOverrides, CorpusFactory), so they mean the same thing under the PHPUnit adapter.

Security

Generated values are pseudo-random (seeded MT19937), not cryptographic. Seeds are not secrets — they are printed in failure output by design. Treat PROPERTY_DB corpus files as test artifacts: they contain generated inputs verbatim, so do not point the variable at a directory that gets published.

Examples

See examples/ — #[Property] test cases run through vendor/bin/testo.

Development

License

BSD-3-Clause


All versions of property-testing-testo with dependencies

PHP Build Version
Package Version
Requires php Version 8.3 - 8.5
rasuvaeff/property-testing-core Version ^1.0
testo/assert Version ^0.1.15
testo/testo Version ^0.10.39
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package rasuvaeff/property-testing-testo contains the following files

Loading the files please wait ...