Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Phpunit Accelerator Laravel Package

padraic/phpunit-accelerator

padraic/phpunit-accelerator is a PHPUnit extension that speeds up test execution for PHP projects. It helps shorten feedback loops by reducing time spent waiting on test suites, making it easier to iterate quickly while continuing to use PHPUnit.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you write a single line of config, do a compatibility check — it will determine whether the rest of this document applies to you at all.

Step 1: Read composer.json, not the README. The package is a PHPUnit listener, which means it is welded to the PHPUnit test-runner API. Check the phpunit/phpunit constraint in require-dev. If it says ~4.0 or ~5.0, you are looking at the PHPUnit_Framework_TestListener interface era. If it says ^6.0–^9.0, it targets PHPUnit\Framework\TestListener. This matters because PHPUnit 10 removed the listener API entirely (deprecated in 9, deleted in 10) in favour of the PHPUnit\Runner\Extension\Extension + Facade model. Laravel 10/11 ship PHPUnit 10/11 by default, so on a modern app this package will either fatal on the missing interface or be silently ignored depending on how the class is referenced.

Step 2: Read src/ first, before installing. With a repo this small (12 stars, 0 dependents, last-touched years ago) the entire value is one or two classes. Read what the listener actually hooks (startTestSuite, endTest, startTest, assertion counting) and decide whether the saving it claims is still real on PHP 8.x + OPcache + JIT. You are evaluating a technique, not adopting a dependency.

Step 3: Install dev-only and register it in a separate config file.

composer require --dev padraic/phpunit-accelerator
cp phpunit.xml phpunit.accelerator.xml

Then in phpunit.accelerator.xml (legacy schema only):

<listeners>
    <listener class="\Padraic\PhpUnitAccelerator\TestListener"
              file="vendor/padraic/phpunit-accelerator/src/TestListener.php"/>
</listeners>

Verify the exact FQCN and file path from the repo — do not copy from a blog post.

First use case: pick one slow-but-stable testsuite (e.g. your Unit suite, not Feature), run time php artisan test --configuration=phpunit.accelerator.xml --testsuite=Unit, then the same without the listener. Three runs each, because a single wall-clock number is noise. If you cannot demonstrate a double-digit percentage improvement, stop here.

Where to look first if you're on PHPUnit 10+: treat the repo as a reference implementation for a custom extension, not as something you install. The listener body is the interesting artifact; the registration API is dead.

Implementation Patterns

Keep the accelerated config non-canonical. Never let phpunit.xml depend on an abandoned dev dependency — your CI, your IDE runner, and php artisan test all read that file by default. Use phpunit.accelerator.xml locally and leave the shared config clean. If you want it in CI, gate it behind a matrix entry alongside the normal run, so a failure is attributable.

Composer script aliasing keeps the day-to-day ergonomics sane:

"scripts": {
    "test": "php artisan test",
    "test:accel": "php artisan test --configuration=phpunit.accelerator.xml"
}

Because php artisan test is a thin wrapper over the PHPUnit binary, listeners declared in the config file do apply — you don't need to drop down to vendor/bin/phpunit. But artisan test --parallel spawns ParaTest workers, and listener state does not cross process boundaries; each worker gets its own listener instance. If the accelerator relies on anything shared (a static cache, a counter), it will behave differently under --parallel than under a single process. Test both.

Benchmark before/after with JUnit XML, not vibes. --log-junit build/accel.xml and --log-junit build/base.xml give you per-test durations you can diff, which is far more diagnostic than total runtime. If the listener only shaves time off some tests, you'll see which class of tests benefits and can reason about whether it generalises.

Laravel-specific baseline first. In a typical Laravel app the dominant cost is bootstrapping the framework and touching the database per test, not PHPUnit's internal bookkeeping. Before reaching for a listener, confirm you've already taken the maintained wins:

  • DatabaseTransactions instead of RefreshDatabase where the schema is stable
  • --parallel (ParaTest) — this is the real accelerator for Laravel
  • splitting Unit / Feature / Browser suites so fast tests run first and fail early
  • config:cache-friendly test env, no APP_DEBUG reflection overhead

If those are done and you still need the listener's marginal gain, the marginal gain is genuinely marginal. That's the honest day-to-day assessment: on a maintained Laravel codebase, this package's leverage is close to zero.

If you do port it: the extension-point pattern is to implement PHPUnit\Runner\Extension\Extension, subscribe to Test\PreparationStarted, Test\Finished, TestSuite\Finished via the Facade, and register in phpunit.xml under <extensions>. Keep the port in tests/Support/ (or a private package) rather than app/, and make it a no-op when a TEST_ACCELERATOR=0 env var is set so you can bisect failures without editing XML.

Gotchas and Tips

The listener API is gone. This is the single most important gotcha and it invalidates the package for Laravel 10/11 defaults. On PHPUnit 9 it works but emits deprecation noise; on PHPUnit 10+ it is a fatal Interface not found or a class that simply never gets invoked. Do not silence this with symfony/phpunit-bridge — you'll be pinning your whole test suite to an EOL runner.

Abandoned dependency, zero dependents. 12 stars and no dependents means no one is filing issues against it, so any incompatibility with a PHP 8.1/8.2/8.3 minor release will go unnoticed until it breaks your build. Never put this in require; never let a composer update be the thing that discovers it's broken.

Order dependence is the failure mode you'll actually hit. Any acceleration trick that changes process reuse, instance lifecycle, or assertion bookkeeping can mask pre-existing test pollution — or introduce it. If tests pass in isolation and fail in the suite (or the reverse), that's your signature. Bisect by disabling the listener first, then by running --order-by=random with and without it. A suite that only passes in the presence of the accelerator is a suite with hidden coupling.

Global state and static caches. If the listener memoizes anything across tests, tearDown may not reset it. Watch for singleton leakage in Laravel containers and for RefreshDatabase transactions that don't roll back because a static held a connection reference.

Debugging recipe: run with --debug, capture JUnit XML from both configs, diff the per-test durations and the test count (an accelerator that drops tests is a bug, not a speedup). Confirm the counts match exactly — a listener that accidentally short-circuits errors will look like a 40% win.

Extension points worth knowing if you fork it: TestListener::startTest/endTest for per-test timers, startTestSuite for suite-level setup, and PHPUnit's CodeCoverage filters — a common "optimisation" in this genre is skipping coverage instrumentation, which you can get for free with --no-coverage and no dependency at all.

Modern replacements, ranked: brianium/paratest (via php artisan test --parallel), Pest's first-class --parallel, PHPUnit 10+ native --processes-style extensions, and simply making the tests cheaper. Any of these is maintained, and together they'll beat a 2014-era listener on a real Laravel application. Reach for this package only on a legacy project pinned to PHPUnit ≤9 where you've already exhausted them — and even then, vendor the two classes rather than depending on the repo.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect