PHPUnit 13.3 is the conservative default for PHP 8.4 codebases
PHPUnit 13.3 gives PHP projects a familiar test case class, assertions, fixtures, data providers, dependency declarations, test doubles, and a command-line runner. Its job is narrow enough to understand: write code that exercises one unit or behavior, make an assertion, and let the runner report failures to a developer or CI system. It also emits formats used by CI services, while its event system and extension points cover teams that need custom reporting or policy checks.
The current major line requires PHP 8.4. Installation can use the official PHAR, Phive, or Composer. The PHAR is attractive for tool isolation because it bundles dependencies and relocates most of them into separate namespaces. Composer fits teams that already pin development tools in composer.json, though the runner then participates in the project's dependency resolution. Official PHAR releases have signatures and SHA256 hashes, and the PHAR can print its bundled dependency manifest or an SBOM.
Three configuration layers make CI policy visible in PHPUnit 13.3
PHPUnit 13.3 combines 3 configuration layers: built-in defaults, phpunit.xml, and command-line options. That arrangement works well for a shared baseline with stricter one-off runs. Test suites can be selected by name or group, ordered, stopped on a chosen kind of defect, or isolated in child processes. The XML file also centralizes bootstrap code, source paths, logging, environment values, and the rules that decide whether warnings or deprecations fail CI.
Strictness is one of PHPUnit's better reasons to stay close to the base runner. It can flag tests that make no assertions, emit unexpected output, change global state, leak error handlers, or claim coverage they do not exercise. Coverage itself needs PCOV or Xdebug, and the docs recommend loading Xdebug only when debugging or collecting coverage. A green run can therefore mean different things across projects unless the team checks its XML policy into version control.
What happened when we ran it
Our 2026-09-05 sandbox evaluation stopped before execution. commit 2c534d3 was placed in a fresh unprivileged Debian container with 3 CPUs and 8 GB of RAM, but our harness had no supported PHP ecosystem. The repository also had no Dockerfile to supply one. We collected no install, build, or test result, so this review cannot turn the README's short PHAR and Composer instructions into a measured setup claim.
That missing run is a limit on our evidence, not a diagnosis of PHPUnit. The lab log does not say that PHP installation failed, that Composer rejected the dependency graph, or that any test failed. It says the required ecosystem was outside the harness and no repository Dockerfile filled the gap. A buyer should run the exact PHPUnit version against the application's own PHP image, extensions, service fixtures, and phpunit.xml before adopting the score here.
Built-in doubles stop at final classes and static methods
PHPUnit 13.3 can create stubs and mocks from interfaces or extendable classes, automatically generating return values that satisfy declared types. The boundary is explicit: final classes cannot be doubled, and final, private, and static methods cannot be replaced in the normal way. Static doubled methods throw an exception. This pushes code toward injected interfaces, which is often healthy, but it is a hard mismatch for a legacy design built around final concrete collaborators or static calls.
Inheritance has a smaller trap. Open issue 6961, created on 2026-09-05, explains that #[Group] on an abstract parent is not inherited by concrete test classes. The documented workarounds are repeating the attribute or organizing suites by directory, neither of which fits every source-shaped test tree. Fixture hooks have better inheritance support through #[Before] and #[After], which avoid a child setUp() forgetting to call its parent.
Native parallel execution was still open after release 13.3.2
Pull request 6784 for native parallel execution remained open on 2026-09-04, so a team should not buy into PHPUnit 13.3 expecting the proposed --parallel behavior. ParaTest is the direct alternative for distributing an existing PHPUnit suite across processes. Pest changes the authoring style while retaining PHPUnit underneath. Codeception reaches farther into API and acceptance testing when a team wants scenarios and application modules rather than assembling those layers around a unit-test runner.
Project health is unusually easy to read. GitHub showed a push on 2026-09-05, one day after several issue and pull request updates, and release 13.3.2 was published on 2026-08-27. The repository had 20,051 stars and 23 open issues and pull requests when fetched. Those numbers show active maintenance and a large audience; they do not tell us whether commit 2c534d3 passes on a clean PHP host.
The missing lab run lowers confidence in setup, not in project health
PHPUnit has the documentation, release practice, and ecosystem position to remain the safe starting choice for PHP 8.4 teams. The reservation is specific: our 3-CPU, 8 GB sandbox never reached its installer or tests, so we cannot confirm the setup from first-hand execution. Adopt it after one run inside the same PHP image and with the same services used by production. If final-heavy design or immediate multi-process execution defines the job, choose the narrower alternative that addresses that constraint.
