ergebnis/phpunit-slow-test-detector
A PHPUnit extension (Composer package and Phar) that detects slow tests and reports those exceeding a configurable maximum duration after your test run.
What it is (and isn't): ergebnis/phpunit-slow-test-detector remains a dev-only PHPUnit extension that measures per-test wall-clock duration and reports tests exceeding a configured threshold. As of 2.27.0 it is no longer only a console table: the release adds GitHub Actions workflow-command annotations for slow tests (PR #775) and refactors report emission behind an extracted Printer abstraction (PR #785). That is a material change to the integration story, not cosmetic. It still ships no runtime code, no service provider, no container bindings, and stays entirely in require-dev plus a few lines of phpunit.xml.
Architecture fit: Still excellent. Same lifecycle seam (extensions for PHPUnit 10–13), no coupling to application code, no deployable-artifact cost. Two new wrinkles: (a) the extension now writes to a second channel — the CI provider's annotation API via stdout workflow commands — so it has a hosting-environment dependency it did not have before; (b) the Printer extraction creates an internal seam that likely admits alternative output formats later, which is architecturally welcome but is currently an internal refactor, not a documented extension point. Do not assume a supported custom-printer plugin API until the docs say so.
Integration feasibility: Still high, and now meaningfully higher-value. Effort estimate shifts slightly: under an hour for a local console-only run (unchanged), plus roughly a half-day to validate annotation behavior on a scratch PR (GitHub Actions only), on top of the prior one engineering day for threshold tuning. Teams on GitLab CI, Jenkins, or Buildkite get no benefit from the new feature and are back to log-scraping — that asymmetry is worth stating plainly in the ADR so nobody assumes parity across pipelines.
Technical risk: Net reduction in adoption risk, small increase in versioning risk.
warning-level signal; PHPUnit's native enforce-time-limit remains the only actual failing mechanism. Teams wanting enforcement still build it themselves.Key questions for the vendor/owner:
GITHUB_ACTIONS, opt-in config, or unconditional when the env var is present? Does it stay quiet outside GitHub Actions, or emit stray ::warning:: lines into other CI logs?Printer a documented, configurable extension point (custom printer class in phpunit.xml), and does that open a supported machine-readable (JSON) format? This is the answer to the long-standing "dashboards require parsing" gap.php artisan test --parallel/paratest, attribution of setUp/tearDown and data-provider time, Pest v2/v3 compatibility, stderr redirection for log consumers.--log-junit no longer matches the annotation UX without extra plumbing, so the buy case is stronger than in the prior review.Stack fit: Composer-native and Laravel-idiomatic, unchanged. Laravel 10/11/12 ship PHPUnit 10/11/12 with the extensions schema; the snippet drops straight into the root phpunit.xml. Prefer the Composer package over the PHAR (the release includes PHAR-build fixes, but that path remains irrelevant for Composer-managed apps). The new annotation feature is GitHub Actions-specific — treat it as an additive capability, not a replacement for the console report.
Migration path: Still purely additive and reversible, same five-step ratchet, with one insertion:
maximum-duration tuning (unit 100–200 ms; feature/http 1000 ms+).maximum-count for large suites, or accept truncation.Compatibility: Confirm the matrix explicitly. The 2.27.0 support-floor drop (PHP 7.0–7.3 removed) affects a narrow edge: Laravel 8 apps still on PHP 7.3. Everyone on PHP 7.4+ and PHPUnit 9.5+ is unaffected in principle, but pin ^2.27 only after checking the support matrix, and pin ^2.26 if any package in the monorepo still resolves on PHP ≤7.3. Continue constraining to a caret range with lockfile pinning; never *. PHPUnit-major-to-PHP-major pinning (11→8.2, 12→8.3, 13→8.4) still governs the real upgrade cadence. The legacy listeners path for PHPUnit ≤9 is unchanged and still carries the deprecation tax.
Sequencing: (1) add dependency, (2) register extension in one phpunit.xml, (3) verify parity across local + CI + one parallel run, (4) validate annotations on a scratch PR, (5) tune thresholds per suite, (6) publish a short internal note on reading both the table and the annotations, (7) only then consider gating. Do not bundle with a PHPUnit upgrade — the annotation path is new code and you want a clean bisect if output misbehaves.
Maintenance: Low but now marginally higher-attention. This stays in the Renovate/Dependabot stream, but 2.27.0 is the proof that a minor bump can drop PHP runtimes — so stop auto-merging patch/minor bumps for this package and route them to the CI/test-infrastructure owner. Expect a handful of bumps per year plus one meaningful bump per PHPUnit major. Ownership unchanged: whoever owns CI/test infrastructure.
Support: Minimal. No on-call surface, no production exposure, no network path at runtime. Worst realistic incidents are "noisy annotations" and "extension class not found," both fixed by deleting a few lines of XML or a config block. The annotated-output feature raises support load slightly in the first weeks — expect a handful of "why is this PR flagged?" questions until thresholds are tuned and the team learns the signal.
Scaling: Compute overhead remains negligible. The scaling caveat is now twofold: sharded runs still emit per-shard top-N (aggregate "top 10" requires concatenating logs), and sharded runs also annotate per-shard, which means the GitHub annotation cap can be hit sooner than expected and the union of annotations across shards may not equal the global worst offenders. For a 5,000-test suite, maximum-count remains the right knob, but it now governs annotation volume as well as table length — tune it with the annotation cap in mind, not just log readability.
Failure modes to plan for:
::warning:: lines pollute GitLab/Jenkins logs and can trip log scrapers. Verify before rollout.Ramp-up: Still essentially zero for engineers. Budget about 30 minutes for a CI owner to wire the extension, an extra 15–30 minutes to validate annotation behavior, and an hour of senior-engineer judgment on per-suite thresholds. The release strengthens the adopt case — PR-visible feedback is what converts a nice-to-have report into something teams actually act on — so this moves from "adopt opportunistically" to "worth a deliberate, time-boxed rollout," with threshold tuning and annotation validation as the two things that must happen before broad enablement.
How can I help you explore Laravel packages today?