Fix exception message assertions on PHPUnit 13.2 and later - #94
Merged
mbabker merged 1 commit intoSep 15, 2026
Conversation
ConfigurationValuesAreInvalidConstraint passed the caught InvalidConfigurationException object to PHPUnit's exception message constraints. Up to PHPUnit 13.1 those constraints string-cast whatever they were given, so passing the exception happened to work, because Throwable::__toString() contains the message. PHPUnit 13.2 (sebastianbergmann/phpunit#6559) tightened ExceptionMessageIsOrContains, ExceptionMessageIs and ExceptionMessageMatchesRegularExpression to accept only the message string, so every assertion carrying an expected message now fails with "Failed asserting that exception message '' contains '...'", whatever the actual message is. Four tests in this suite are affected. Pass the message instead, which is what PHPUnit itself feeds these constraints. This behaves identically on PHPUnit 10.5 through 13.1, where the constraints string-cast their input, and it also repairs the empty expected message branch, which could never match while an object was passed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mbabker
approved these changes
Sep 15, 2026
Contributor
Author
|
@mbabker thank you! Can you please create a new tag/release since this has been merged? |
Contributor
|
Consider it done, 6.2.1 released. |
Contributor
Author
|
Thank you very much @mbabker ! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Every assertion that carries an expected message fails on PHPUnit >= 13.2, regardless of what the actual exception message is:
This affects
assertConfigurationIsInvalid()andassertPartialConfigurationIsInvalid()whenever$expectedMessageis given, with or without$useRegExp. Calls without an expected message are unaffected.This repository's own test suite is already red. On
masterwith PHPUnit 13.3.4, 4 of 39 tests fail:CI has not caught it because it only runs on
pushandpull_request, and the last run was 2026-02-09, before PHPUnit 13.2.0 was released on 2026-06-05. The matrix does not pin a PHPUnit version, so the PHP 8.4 legs resolve to 13.3.x and will go red as soon as anything reruns.Cause
ConfigurationValuesAreInvalidConstraint::evaluateException()passes the caughtInvalidConfigurationExceptionobject to the PHPUnit constraint. Up to PHPUnit 13.1 that worked by accident, because the constraints string-cast whatever they were given andThrowable::__toString()contains the message:PHPUnit 13.2.0 (sebastianbergmann/phpunit#6559, "Improved API for exception message expectations") tightened
ExceptionMessageIsOrContains,ExceptionMessageIsandExceptionMessageMatchesRegularExpressionto accept only the message string:PHPUnit itself now always feeds these constraints
$exception->getMessage()(seePHPUnit\Framework\TestCase\ExceptionExpectation::verify()). The classes are marked@internalin PHPUnit, so this is not a BC break on their side.Fix
Pass the message rather than the exception. One line, and it covers both the plain and the regexp paths since they share the call site.
Compatibility
Verified locally on PHP 8.4.25, running the full suite against each supported major:
On 10.5 through 13.1 the constraints do
str_contains((string) $other, ...), which is identical for a plain string, so nothing changes there. The change also repairs the$expectedMessage === ''branch, which could never match while an object was passed.Test
Added
the_failure_message_contains_the_actual_exception_message, which asserts that a mismatched expectation reports the real message. Reverting the one-line fix makes it fail with:The four pre-existing failures listed above also turn green.
Relation to #91
#91 removes the unreachable PHPUnit 9.6 (
ExceptionMessage) and PHPUnit 10.0.0-10.0.14 (MessageIsOrContains) fallbacks fromcreatePhpUnitConstraint(), which are dead code givencomposer.jsonrequiresphpunit/phpunit: ^10.5 || ^11.0 || ^12.0 || ^13.0. That cleanup is worth having and I have deliberately not duplicated it here.Note that #91 does not fix this bug: it keeps passing
$exceptiontoevaluate()in both branches, so the suite stays red on PHPUnit >= 13.2. The two changes touch the same lines and will conflict textually, so whichever lands second needs a trivial rebase:->evaluate($exception->getMessage(), ...)in each of its two branches. Happy to rebase and push.$exception->getMessage()through.🤖 Generated with Claude Code