The @expectedException annotation asserts that the exception happened somewhere in the method, which passes when it is thrown by the setup rather than by the thing under test.
// what it was
/** @expectedException AppPaymentDeclined */
public function testDeclined() { /* ... */ }
// what it should be — the assertion is next to the call
public function testDeclined(): void
{
$gateway = new Gateway($this->declinedClient());
$this->expectException(PaymentDeclined::class);
$this->expectExceptionMessage('insufficient funds');
$gateway->charge($this->card, Money::gbp(4900));
}
Placing the expectation immediately before the call is the whole improvement — everything above it is arrangement and is asserted normally. The annotations are deprecated in 8 and gone in 9, so this is a migration with a deadline. expectExceptionMessage does a substring match rather than an equality one, which is usually what you want and occasionally matches something you did not intend.