Download the PHP package rasuvaeff/understudy-phpunit without Composer
On this page you can find all versions of the php package rasuvaeff/understudy-phpunit. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download rasuvaeff/understudy-phpunit
More information about rasuvaeff/understudy-phpunit
Files in rasuvaeff/understudy-phpunit
Package understudy-phpunit
Short Description PHPUnit adapter for the understudy test double library: automatic verification and cleanup after every test
License BSD-3-Clause
Homepage https://github.com/rasuvaeff/understudy-phpunit
Informations about the package understudy-phpunit
rasuvaeff/understudy-phpunit
PHPUnit adapter for rasuvaeff/understudy —
a test double library where a configured call is a real call:
when(fn () => $repo->find(123))->returns($book).
The trait ends every test with understudy's own bookkeeping done for you:
- verify after success — after a body that reaches
assertPostConditions(), everyexpect()is checked. An expectation the code never fulfilled fails the test as an assertion failure; - original failure wins — after a failing body nothing is verified, so the adapter can never mask the error that actually happened;
- reset always — an
#[After]hook drops the context unconditionally. One test can never leak a double into the next; - early guard — an
#[Before]hook refuses to start over a context some earlier test left behind, which is what broken integration looks like.
The reset runs after your tearDown(). PHPUnit invokes #[After] hooks
once tearDown() has finished, and the call log retains every returned value
until that reset — so a value a double returned is still referenced while your
teardown runs. For a value that owns an OS resource — a stream, a connection,
a lock — the resource is still held: a forwarding double that returned real
file streams made teardown's directory removal fail with "Directory not
empty", on Windows only, because POSIX unlinks open files. Build such a double
lean (Understudy::lean($double) keeps calls, not returned values), or build
and use it inside Understudy::scope(), which drops the context before
teardown.
Using an AI coding assistant? llms.txt is a compact API reference it can load instead of guessing.
Requirements
- PHP 8.3 – 8.5
phpunit/phpunit(^11.5 || ^12.0 || ^13.0)rasuvaeff/understudy(^1.0)
Pest works too — it runs on PHPUnit, so the same trait applies through
uses(). Proven against Pest 4; see the Pest section below.
Installation
Usage
One registration says both things: find(7) must be called exactly once, and
it answers $expected. If the service never calls it, the test fails after its
body — with an unmet-expectation report naming the call, not with a silent
green.
Two rules of the engine decide that shape, and both are easy to miss coming from another library:
- Arm before the run. An
expect()counts only the calls that arrive after it is declared. Written below the action it counts zero and fails as "called never" about a call that did happen. To claim a call that already happened, useverify(). - One registration per call. A
when()stub and anexpect()naming the exact same call are refused withConflictingExpectation— whichever came later would take the dispatch and silently void the other. Say both things once:expect(...)->returns(...), orwhen(...)->times(...).
Strict stubs
A base class can flip strictness for a whole project:
A stub configured but never called then fails its test — the Mockito reading
of "why did you configure it, then?". There is no per-double form of it:
Understudy::strict($double) is strict dispatch — "fail on any call no
expectation matched" — and says nothing about a stub that was configured and
never called. The per-double equivalent is when(…)->times(n).
Verification runs before your teardown here, and after it under
understudy-testo. assertPostConditions() is called by PHPUnit before
tearDown(); the Testo interceptor runs outside #[AfterTest]. Neither is
wrong, but a test whose expectation is fulfilled by teardown itself fails here
and passes there. reset() runs after teardown in both.
A test that creates no double is not touched at all: nothing is counted for it,
so #[DoesNotPerformAssertions] keeps meaning what it says.
Overriding assertPostConditions() yourself
PHP resolves a method-name conflict between class and trait silently in favour of the class — the trait's verification would stop running without any error. Compose explicitly:
The trait runs parent::assertPostConditions() before verifying, so your own
post-conditions always run and their failure is reported ahead of an unmet
expectation — the check closer to the test body wins. Keep that order in an
explicit composition too.
An override that forgets to compose is not silent: a body that passed, held
doubles, and never reached the trait's verification fails in the #[After]
hook with this recipe in the message — and the context is still reset.
Pest
Pest already owns the global expect() function, so import understudy's
setup verb under another name:
expect() is a claim made before the code under test runs — it counts the
calls that arrive after it, not the ones that already happened. Reading a call
back after the action is verify(). Pest's own expect() keeps working
untouched, and the collision-free static form
Understudy::when()/expect()/verify() works everywhere as well.
Both spellings are executed by tests/Integration/Fixtures/Pest, a Pest
project of its own; make test-pest installs and runs it.
API
| Member | Purpose |
|---|---|
UnderstudyPHPUnitIntegration |
The trait: verify-after-success, reset via #[After], #[Before] guard, optional project-wide strict stubs |
Everything else — for(), when(), expect(), verify(), matchers,
forwarding, wire() — belongs to
rasuvaeff/understudy and is
documented there. This package adds no operations of its own.
Security
The trait hooks #[Before]/#[After] around each test and, on a passing
body, calls the engine's verifyAll(). It executes no code beyond what the
test itself runs and writes nothing.
Examples
See examples/.
The understudy family
| Package | What it is |
|---|---|
| rasuvaeff/understudy | The engine: doubles, matchers, expectations, verification. |
| rasuvaeff/understudy-testo | Testo adapter — verification and reset around every test. |
| rasuvaeff/understudy-phpunit (this package) | PHPUnit and Pest adapter — the same, through a trait. |
| rasuvaeff/understudy-psalm | Psalm plugin — matcher-aware specifications and misuse diagnostics. |
| rasuvaeff/understudy-phpstan | PHPStan extension — the same for PHPStan, plus its own rules. |
Development
No PHP/Composer on the host — everything runs through Docker:
Or with Make: make build, make cs-fix, make psalm, make test.
The integration suite spawns real PHPUnit processes over fixture projects in
tests/Integration/Fixtures/; it needs no external services.
License
BSD-3-Clause
All versions of understudy-phpunit with dependencies
phpunit/phpunit Version ^11.5 || ^12.0 || ^13.0
rasuvaeff/understudy Version ^1.0