Skip to content

Has everything been described? ​

php
Understudy::nothingElse($repository);                    // every call was accounted for
Understudy::nothingElse($repository, $clock, $mailer);   // across several doubles
Understudy::allVerified($repository);                    // expectations met AND nothing else

What counts as accounted for ​

Accounts for a call
An expect() that matched ityes
A successful verify() that claimed ityes
A failed verify()no
A when() stubno

A stub accounts for nothing because it is permission, not a description of what happened. This is the rule that makes nothingElse() worth having: a test can stub freely and still assert that the subject made no call it did not mean to.

Why one line, many doubles ​

nothingElse() takes any number of doubles, so one line closes out the whole test. A failure names every offender rather than stopping at the first — the second unexpected call is usually as interesting as the first, and finding it one run at a time is the slow way.

The trap this closes ​

A spy-style test that counts calls will happily pass while the subject also makes a call with entirely different arguments:

php
expect(fn () => $repository->save($expected));
// subject also calls $repository->save($somethingElse) — still green

expect() claims the calls it matched. It says nothing about the rest. Add nothingElse(), or use allVerified(), which is both checks in one:

php
Understudy::allVerified($repository);

allVerified() checks ordered expectations too.

See the cookbook case for the full worked example — it is the trap people carry over from Mockery most often.