Download the PHP package italix/testing without Composer
On this page you can find all versions of the php package italix/testing. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download italix/testing
More information about italix/testing
Files in italix/testing
Package testing
Short Description In-process PSR-15 HTTP client, schema-derived row factories, rollback isolation and a plain test runner
License MPL-2.0
Homepage https://github.com/italix-net/testing
Informations about the package testing
Italix Testing
An in-process HTTP client, row factories derived from the schema, rollback isolation, and a runner that is a function and two counters.
Zero test-framework dependencies. Engine is already PSR-15 and Table already describes every
column, so most of this library is glue that was missing rather than machinery that is new.
The client
pipeline() or boot() — the difference matters.
| What it drives | |
|---|---|
ix_client($engine->pipeline()) |
the full stack: locale, CSRF, authentication, routing, controller, view |
ix_client($engine->boot()) |
routing and controller only, no global middleware |
Use the first by default. A test that uses the second is not evidence that a route is reachable, only that the action works.
Sessions behave like a cookie jar
as() seeds the session; whatever the application writes during a request is visible to the next
request made through the same instance. That is what lets a redirect-then-follow test see its flash
message.
as(), with_header() and with_csrf() each return a new client, so a seeded client cannot
leak into an anonymous one by accident.
CSRF is opt-in
Automatic injection would make the test that matters most impossible to write.
Factories
Rows come from the schema, not from a fixture file:
| Column | What the factory does |
|---|---|
| primary key | left to the database |
not_null(), no default |
filled with a type-appropriate value, truncated to the declared length |
| nullable | left out, so the values a test does set stand out |
| has a default | left to the database — only it knows what CURRENT_TIMESTAMP means |
| unknown type | stops the run, naming the column and the type |
unknown column in with() |
stops the run — usually a typo |
Values are deterministic (test_1, test_2, …) drawn from a process-wide sequence, not random: a
suite that fails must fail again on the next run.
The point of deriving from the schema is what happens later. A migration that adds a not_null()
column leaves a hand-written fixture inserting a row the database no longer accepts, and the test
fails somewhere unrelated to what it was checking. A derived factory fills it.
Isolation
Rollback rather than truncation: truncating destroys the reference data an application needs to boot — countries, provinces, the seeded admin — and rebuilding it is a second fixture that drifts from the first. A rollback leaves the database exactly as it was found, which also means a suite can run against a development database without being a risk to it.
The rollback happens whether the closure returns or throws, and an exception propagates unchanged —
the isolation is a side effect, not a catch.
Two limits, stated rather than discovered:
- MySQL commits DDL implicitly. A test that creates or alters a table escapes the rollback. Migrations are not testable this way.
- Nesting is refused, not emulated. Savepoints would make the failure mode subtle; an exception makes it obvious. A commit inside the closure is reported for the same reason.
The runner
$details prints only on failure, so it can afford to be expensive to read: the actual value, the
offending input, the query that ran.
suite() also starts the PHP session before printing anything — see below.
JUnit, for whatever reads the build
Written as well as the human output. A build server does not read ticks, so a suite either passed or failed and the hundred assertions inside it were a wall of scrollback; every CI in common use consumes JUnit XML and turns it into per-assertion annotations on the diff.
section() becomes JUnit's classname, which is what those tools group by — so a heading reading
"the two halves of a message are not equally trustworthy" arrives in the report as the heading it
already was. A path ending in / receives one file per suite; anything else is the file to write.
Control characters are stripped before escaping: a failure detail can hold an HTTP body or a byte out
of a fuzzer, and a \x00 is never legal in XML 1.0 — entity-encoded or not — so one of them would
make the whole report unparseable and the build would report nothing at all.
From PHPUnit, without rewriting anything
Not because PHPUnit is better — these suites read as prose and a class-and-method convention flattens that. It is about who can run them: checking out one of these libraries and running its tests otherwise means first installing this package, and a maintainer evaluating an i18n library will not install somebody's test framework to see whether the i18n library works.
One suite file becomes one PHPUnit test, in a child process, asserting on the exit code. Do not
enable processIsolation on top of it — several suites boot one application and send it several
requests specifically to reproduce a resident worker, and isolating those per test removes the
condition under test.
Two behaviours worth knowing
Sessions must start before any output. Measured on PHP 8.1 CLI: the first printed byte sets
headers_sent(), after which session_start() cannot succeed and passing options does not help.
suite() therefore starts it first. If it is too late, $_SESSION is still an ordinary array and
everything works — application middleware cannot tell the difference — but that middleware's own
session_start() call will warn into the middle of the results.
TestingException is not a failed assertion. A failed test() is a result; a TestingException
is the harness saying it does not know what to do — an unknown column type, an identifier it refuses
to interpolate, a transaction it cannot roll back. Those stop the run, because a harness that
guesses produces green suites that mean nothing.
All versions of testing with dependencies
ext-json Version *
italix/contracts Version ^2.0
psr/http-message Version ^1.0 || ^2.0
psr/http-server-handler Version ^1.0
guzzlehttp/psr7 Version ^2.0
psr/http-server-middleware Version ^1.0