crodas/phpunit-compat
A PHPUnit compatibility package that helps bridge version differences, making test suites easier to run across varied PHPUnit environments with fewer compatibility issues.
Architecture fit. crodas/phpunit-compat is a single-purpose compatibility shim, not a framework or library. Its implied architecture is a Composer files autoload entry that registers class_alias mappings so that pre-6.x PHPUnit symbols (PHPUnit_Framework_TestCase, PHPUnit_Framework_MockObject_MockObject, etc.) resolve to their namespaced PHPUnit\Framework\* equivalents introduced in PHPUnit 6. For a Laravel codebase this means it sits entirely in require-dev, participates only in the test bootstrap, and has zero production runtime surface. That is architecturally clean and easy to reason about — the concern is not where it sits but what it cannot do.
Integration feasibility. Mechanically trivial: add the dev dependency, ensure autoload ordering puts the shim ahead of test class loading, run the suite. The hard part is that class aliasing only fixes name resolution, not behavioral drift. PHPUnit 6 changed more than namespaces: getMock() was replaced by createMock(), mock builder APIs and MockObject contracts shifted, assertContains semantics for strings were deprecated, setUp() signature expectations changed, and several assertions/prophecy interactions moved. A suite that "passes" through aliasing may be silently exercising different code paths than it did on 5.x, which is the worst possible outcome for a test harness — false confidence.
Technical risk. High, concentrated in provenance rather than complexity. The package self-describes as a "Hack," carries 0 stars and 0 dependents, and has no community validation, no downstream consumers to surface breakage, and presumably no CI matrix against multiple PHPUnit/PHP versions. It is almost certainly a single-maintainer artifact pinned to a narrow window (PHPUnit 6.0–6.5, PHP 7.0–7.1 era). Supply-chain exposure is low in blast radius (dev-only) but nonzero: an unmaintained files-autoloaded package executes arbitrary code at bootstrap on every test run and every CI job. Abandonment risk is effectively certain — PHPUnit 6 is itself EOL, and current Laravel supports PHPUnit 9/10/11.
Key questions.
collision/phpunit pins?TestCase and mock objects, or does it cover assertions, constraints, and TestCase static helpers?Stack fit. This only fits a narrow historical slice: a Laravel 5.5/5.6-era application whose test suite was written against PHPUnit 5.x conventions but whose dependency graph has been bumped to PHPUnit 6.x, typically as a side effect of a PHP 7 upgrade or a composer update. Modern Laravel (9+) has no use for it. If the codebase already uses namespaced PHPUnit\Framework\TestCase, the package is dead weight and should not be introduced.
Migration path. Treat it as a temporary bridge, never a destination. The preferred sequence is: (1) inventory test files by legacy symbol usage — grep for PHPUnit_Framework_, getMock(, setExpectedException, and underscore-style assertions; (2) run an automated rewrite (Rector's PHPUnit rulesets or PHPUnit's own migration guidance) to namespaced classes and current APIs; (3) fix behavioral gaps surfaced by the rewrite; (4) delete the shim. If the rewrite cannot be completed before a deadline, adopt the package behind an explicit removal ticket with an owner and a date — do not let it accrete.
Compatibility. Verify against the exact matrix in composer.json: PHP version, PHPUnit constraint, and any conflict/replace entries. Run composer why-not phpunit/phpunit 6.5 to confirm nothing else pins. Because it autoloads via files, confirm with composer dump-autoload -o in CI that alias registration still precedes test bootstrap; optimized autoloaders have historically changed files ordering behavior.
Sequencing. If adopted at all: pin an exact version (no caret range) and commit composer.lock; land it in a single PR that touches only composer.json and the test bootstrap; run the full suite and diff the test count and assertion count against the pre-change baseline to catch tests that silently stopped being discovered. Only then proceed with incremental file-by-file migration. Prefer, where feasible, forking the shim into an internal dev-compat namespace under team ownership — a ~50-line class_alias file is cheap to own and eliminates the abandoned-dependency risk entirely.
Maintenance. Effectively zero upstream maintenance expected. Budget for the team owning it internally, or budget for the migration that removes it. The real maintenance cost is the migration debt it defers: every sprint it stays, more test files are written against aliased legacy symbols, deepening the eventual rewrite.
Support. No vendor, no maintainer SLA, no issue triage. Internal engineers must debug PHPUnit internals if an alias is missing or misordered. Documentation is the README, which by the description is a one-liner. Escalation path is "read PHPUnit 6's upgrade notes and write the alias yourself."
Scaling. Not a runtime concern — it is dev-only and never ships to production, so it has no bearing on request throughput, queue workers, or horizontal scaling. The scaling concern is organizational: CI wall-clock and developer friction grow with suite size, and legacy-style tests often carry slower setup patterns. If the suite is large, the shim's inability to enforce modern APIs will slow the eventual parallelization/CI investment.
Failure modes. (1) Silent under-discovery — alias gaps cause test classes not to be collected, so the suite passes with fewer tests; the assertion-count diff is the only reliable guard. (2) False passes from behavioral drift — aliases resolve names but not semantics, so tests may assert against changed mock behavior. (3) Autoload ordering breaks — optimized autoloaders, PHPUnit's own bootstrap ordering, or a phpunit.xml bootstrap change can load test classes before aliases register, producing fatal Class not found errors that look like package breakage. (4) Composer resolution conflicts when another dev dependency tightens the PHPUnit constraint. (5) Abandonment without warning — no deprecation notice will arrive; the package will simply stop working on a future PHP minor.
Ramp-up. Near-zero learning curve for a developer to use it (add dependency, run tests). Non-trivial to understand it: a new engineer inheriting the repo sees a zero-star, zero-dependent "hack" package in require-dev with no explanation and no removal plan, and must reverse-engineer why it exists. Mitigate with an inline comment in composer.json or a short ADR recording the reason, the owner, and the exit criteria.
Bottom line. Low adoption opportunity (score 16.63 reflects this): the addressable window is small, the package is unvalidated and unmaintained, and the correct strategic move for almost any Laravel team is either a codemod/Rector migration or an internally owned ~50-line alias file. Approve only as a dated stopgap with an explicit removal ticket, never as a standing dependency.
How can I help you explore Laravel packages today?