sebastianbergmann/phpunit · error · ExpectationFailedException

Expected deprecation with message

Error message

Expected deprecation with message "%s" was not triggered

What it means

Thrown after the test body finishes when expectDeprecation() was called but DeprecationCollector never recorded a matching user deprecation. PHPUnit verifies outstanding deprecation expectations in verifyDeprecationExpectations() during runBare(), so a missing deprecation is treated as a failed assertion.

Solutions

  1. Verify the code under test actually executes the branch that triggers the deprecation in this test
  2. Compare the expected string byte-for-byte with the trigger_error() message; fix typos or interpolated values
  3. Switch to expectDeprecationMatch() with a regex when the message contains variable parts
  4. Ensure the deprecation is triggered in the same PHP process (avoid process isolation for this test)

Example fix

// before
$this->expectDeprecation('Using Config v2 is deprecated');
$api->load("v3"); // never touches the deprecated v2 path

// after
$this->expectDeprecation('Using Config v2 is deprecated');
$api->load("v2"); // exercises the deprecated path
Defensive patterns

Strategy: validation

Validate before calling

// Before the test: confirm the expected deprecation is among collected ones in this process
$this->expectDeprecation('Config v2 is deprecated');
$api->load('v2');
self::assertContains(
    'Config v2 is deprecated',
    DeprecationCollector::deprecations(),
);

Try / catch

// When wrapping third-party tests, let the failure surface instead of swallowing it:
try {
    $test->runBare();
} catch (ExpectationFailedException $e) {
    if (!str_contains($e->getMessage(), 'Expected deprecation with message')) {
        throw $e;
    }
    // record as deprecation-missing failure
}

Prevention

When it happens

Trigger: Calling $this->expectDeprecation('exact message') but the code under test never calls trigger_error($msg, E_USER_DEPRECATED) with exactly that message, or the deprecation fires in a separate process from the one collecting them.

Common situations: Message typos or dynamic parts in the deprecation string (use expectDeprecationMatch() for those); the deprecated code path not being reached by this test; process isolation splitting the collector; library versions changing deprecation wording.

Related errors


AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23). Data as JSON: /api/errors/d7af430359cb5d4c. Report an issue: GitHub.

Appendix: source

Thrown at src/Framework/TestCase.php:1505

            $this->errorLogCapture->stop();
        }

        $this->emitEventForCustomTestMethodInvocation();
        $this->exceptionExpectation->assertWasRaised($this);

        return $testResult;
    }

    /**
     * @throws ExpectationFailedException
     */
    private function verifyDeprecationExpectations(): void
    {
        foreach ($this->expectedUserDeprecationMessage as $deprecationExpectation) {
            $this->numberOfAssertionsPerformed++;

            if (!in_array($deprecationExpectation, DeprecationCollector::deprecations(), true)) {
                throw new ExpectationFailedException(
                    sprintf(
                        'Expected deprecation with message "%s" was not triggered',
                        $deprecationExpectation,
                    ),
                );
            }
        }

        foreach ($this->expectedUserDeprecationMessageRegularExpression as $deprecationExpectation) {
            $this->numberOfAssertionsPerformed++;

            $expectedDeprecationTriggered = array_any(
                DeprecationCollector::deprecations(),
                static fn (string $deprecation) => @preg_match($deprecationExpectation, $deprecation) > 0,
            );

            if (!$expectedDeprecationTriggered) {
                throw new ExpectationFailedException(

View on GitHub (pinned to f123cdb2a2)