PHPUnit

PHPUnit 13

Major Release

The PHPUnit development team is pleased to announce the release of PHPUnit 13. This release introduces new features and modifies or removes existing functionality.

A detailed list of changes can be found here. The most significant changes are discussed below.

OMGWTFBBQ? I must upgrade to PHPUnit 13 immediately!

No, you do not.

Just because PHPUnit 13 has been released today does not mean that PHPUnit 11 or PHPUnit 12 will no longer work. While old versions of PHPUnit will eventually stop receiving bug fixes, we will keep them compatible with new versions of PHP for as long as possible.

We sincerely hope that you do not use the Death Star Version Constraint and therefore do not automatically and unintentionally upgrade to a new major version of PHPUnit.

Upgrading a dependency to a new major release must be a conscious decision that is part of a defined process. This process should include, at a minimum, reading an announcement like this and the ChangeLog.

PHPUnit 13 requires PHP 8.4 or later. If you are not using PHP 8.4 or PHP 8.5, you will not be able to use PHPUnit 13 right away.

We are confident that PHPUnit 13 works as intended, but in some respects it works differently than previous versions.

For example, functionality that was only soft-deprecated in PHPUnit 12 is now hard-deprecated in PHPUnit 13. And functionality that was hard-deprecated in PHPUnit 12 has been removed in PHPUnit 13. You can find details about deprecations here:

You should not even try to upgrade to PHPUnit 13 if you cannot run your test suite using PHPUnit 12.5 without getting deprecation warnings.

If the above does not put you off, then please: go ahead and upgrade! And should you encounter a problem, please report it.

Major Changes in PHPUnit 13

New array assertions

PHPUnit 13 introduces new assertions to address a long-standing need for more precise array comparison semantics beyond the general-purpose assertSame() and assertEquals() methods.

These new assertions operate along three distinct dimensions:

  • comparison strictness (identical using strict type checking versus equal using loose comparison)
  • key consideration (whether array keys must match or only values matter)
  • order sensitivity (whether element order is significant or can be ignored)

This systematic approach eliminates the ambiguity that often arose when developers needed to compare arrays with specific requirements, such as verifying that two arrays contain the same values regardless of key names or order, or ensuring that associative arrays are strictly identical including key ordering.

A replacement for withConsecutive()

PHPUnit 13 introduces refined parameter matching capabilities for mock objects, addressing longstanding limitations in test double verification.

The removal of withConsecutive() and its replacement with two specialized rules for validating parameter sets across multiple invocations eliminates the need for the verbose workarounds that developers had to implement when upgrading to PHPUnit 10.

This evolution reflects a deeper commitment to making mock object assertions more intuitive and maintainable, allowing developers to express complex call verification scenarios with cleaner, more readable code.

Sealed test doubles

PHPUnit 13 introduces sealed test doubles, a powerful new feature that prevents common mocking pitfalls by finalising a test double's configuration and enforcing strict expectations.

When a test double is sealed using the new seal() method, it disallows any further configuration through expects() or method() calls, ensuring that mock objects are fully configured before the system under test is exercised.

On mock objects specifically, sealing implicitly configures all methods without explicit expectations to reject invocations that were not explicitly configured as expected. This feature addresses long-standing testing challenges where developers inadvertently configured mock objects after using them, or where tests passed despite unexpected method calls because unconfigured methods simply returned null.

Sealed test doubles provide a clear contract: once the configuration is finalised, the test double becomes a reliable, immutable fixture that accurately reflects the intended behavior of dependencies, making tests more robust and maintainable while catching unintended interactions that would otherwise go unnoticed.

This purely additive feature requires no changes to existing test suites, allowing developers to opt in where stricter test double behavior provides value.

The any() matcher is now hard-deprecated

The deprecation of the any() matcher reinforces a fundamental principle: mock objects are verification tools designed to assert that specific interactions occur, not to silently ignore them.

By eliminating the conceptual contradiction inherent in creating a mock object while declaring indifference to its invocation, PHPUnit 13 encourages developers to make deliberate choices: either using specific matchers like once() or exactly() for true verification concerns, or migrating to test stubs when no verification is needed.

This shift promotes clearer test intent and eliminates the performance overhead of mock objects in scenarios where they provide no actual verification value.

Supported Versions

Detailed information on supported versions of PHPUnit is available here. Below is a summary as of February 6, 2026:

  • PHPUnit 13 receives bug fixes until February 4, 2028
  • PHPUnit 12 receives bug fixes until February 5, 2027
  • PHPUnit 11 and older versions no longer receive bug fixes

The versions listed above will be kept compatible with new PHP versions as long as possible.

Looking Forward

Here is the roadmap for the next year:

Keep up to date with PHPUnit

You can follow @[email protected] to stay up to date with PHPUnit's development.

You can subscribe to the PHPUnit Updates newsletter to receive updates about and tips for PHPUnit.