Skip to content

The stub nobody used ​

A stub is permission, so an unused one is silent by default. That is right on the day the test is written and wrong a year later, when the stub describes a call the code stopped making.

The test ​

php
$repository = Understudy::for(BookRepository::class);

when(fn () => $repository->find(7))->returns(new Book('Dune'));

// This one described a call the subject stopped making when the lookup moved
// to find(). Nothing fails by default: a stub is permission.
when(fn () => $repository->findBySlug('dune'))->returns(new Book('Dune'));

$repository->find(7);

Understudy::verifyAll();

What it reports ​

With strictStubs turned on:

text
verifyAll() alone: passed

Understudy `BookRepository` has a stub for `findBySlug('dune')` that was never used.
Remove it, or drop strictStubs if the call is genuinely optional.

Why this was the bug ​

The lookup moved from findBySlug() to find(), and the test was updated by adding a stub rather than replacing one. Both stubs sat there; the subject used one. The test kept passing, and it kept describing a collaborator that no longer had that shape.

That is the signal strict stubs buys: not "you wrote a stub you did not need", but "this test still believes something about the code that stopped being true".

Turning it on ​

Project-wide, on a base class or in the plugin — not per test. See Strict stubs for each runner, and for why it is off by default.

Not the same as a strict double

verifyAll(strictStubs: true) is about registrations nobody used. Understudy::strict($double) is a mode, about calls nothing configured accepted — and it fails at the call, not at verification.