Skip to content

Phases, scopes and transcripts

php
Understudy::checkpoint();                       // verify, then forget what is settled
$result = Understudy::scope(fn () => ...);      // nested context, verified on success
echo Understudy::transcript($repository);       // every call and its outcome
Understudy::idle();                             // true when the context holds no doubles

The context

A context owns doubles, their registrations and their transcripts.

  • checkpoint() keeps the understudies, their modes and their labels while clearing what the current phase has settled. Useful when one test walks through several stages and each stage has its own claims.
  • scope() opens a nested context, runs the callback, and drops the context either way. It returns whatever the callback returns, and a failure inside is never replaced by a teardown error.

A double created in a scope is invalid after that scope closes.

Configuration and verification belong to the owner

They must run in the context that owns the double. Ordinary calls may be made from another fiber and are still recorded in the owner's log — see Fiber isolation.

Reading the call log

php
use Rasuvaeff\Understudy\Arg;

$calls = Understudy::calls(fn () => $repository->find(Arg::any()));

$calls[0]->args;          // [123]
$calls[0]->didReturn();   // true
$calls[0]->returned();    // the value it answered with
$calls[1]->thrown();      // the throwable, if it threw

null is a valid return value, which is why the outcome is asked about (didReturn()) rather than inferred from the value.

php
$last = Understudy::lastCall(fn () => $repository->find(Arg::any()));

$last?->args;   // the newest matching call, null when there was none

lastCall() is the null-safe replacement for count($calls) - 1: an empty log has no last element, and static analysis cannot prove otherwise, so the index arithmetic reports int<-1, max> before the test even runs.

The transcript

transcript() renders every call and its outcome, and retains every invocation until reset() or checkpoint().

Avoid unbounded hot loops through a double when the arguments or results hold large object graphs; use a real fake for load-sized workloads. Where the retained thing owns an OS resource rather than memory, see Retention and lean() — that is a correctness problem, not a size one.

Cleaning up

php
Understudy::reset();
Understudy::idle();   // true when the current context holds no doubles

The Testo and PHPUnit adapters verify and reset for you after every test. Without one, call reset() in your own teardown.