Testing a class that takes an interface usually means either a mocking framework or a small stub class in its own file, which then lives forever and is used by three unrelated tests that all need it to behave differently.
$gateway = new class implements Gateway {
public $charged = [];
public function charge(int $cents): Receipt
{
$this->charged[] = $cents;
return new Receipt('test');
}
};
$checkout->pay($gateway);
$this->assertSame([4900], $gateway->charged);
The double is defined where it is used, so its behaviour is visible in the test rather than in another file, and it cannot accidentally be reused. It is a better fit than a mock when the assertion is about state rather than about interaction. Each evaluation creates a distinct class, so do not put one in a loop and expect them to share anything.