Product Decisions This Supports
- Test-suite velocity as a roadmap item. This package is a lever for the "PR feedback under 10 minutes" class of initiatives. It lets you evaluate whether concurrency (Swoole coroutines inside one PHP process) can shrink wall-clock time on tests that are dominated by
sleep(), usleep(), retry backoff, HTTP fakes with latency, and polling loops — without forking N processes.
- Build vs. buy vs. refactor. Three competing options for the same problem: (a) adopt
counit, (b) buy/extend process-level parallelism (ParaTest, Pest parallel, CI sharding), (c) refactor tests to stop waiting — Laravel's Sleep::fake(), Http::fake(), Queue::fake(), Carbon::setTestNow(), and time-travel helpers. This package only earns a slot when (c) has been exhausted and (b) is capped by machine count or shared-DB contention.
- Feature-area prioritization. Retry/backoff, rate limiting, webhook polling, queued-job delay, and third-party integration tests are the natural beneficiaries. If those areas are on the roadmap, their test cost grows with them; this is a way to keep that growth sublinear.
- Platform standardization on Swoole. If the org already runs Laravel Octane on Swoole, adoption is an incremental extension of an existing runtime dependency. If not, this decision quietly puts a PECL extension on every developer machine and CI image — a platform decision, not a test-tooling decision.
- CI spend and release cadence. Shorter suites correlate with smaller PRs, more frequent merges, and lower CI minute cost. Both are measurable in the pilot: p50/p95 suite duration, CI minutes per week, flaky-test rate, and merge frequency.
- Engineering standards. Adopting it forces a written policy on coroutine safety: no shared mutable statics, per-coroutine DB connections, no assumptions about global container state, no cross-test leakage.
- Not supported: it is not a test-isolation framework, not a mocking library, and not a substitute for removing unnecessary waits. Do not let it become a reason to keep real sleeps in tests.
When to Consider This Package
Consider it when:
- The suite has a measurable tail of slow tests whose time is waiting, not computing — sleeps, backoff, polling, timed retries. Profile first; if CPU-bound, this will not help.
- Swoole is already approved and installed (Octane, or an existing coroutine service), so the marginal operational cost is near zero.
- Tests are already reasonably isolated: fresh application instance per test, no reliance on static/global state, no shared in-memory caches.
- Database access can be made coroutine-safe — separate connections per coroutine or a pool.
RefreshDatabase with a single shared connection across concurrent coroutines is a known trap.
- You can pin PHPUnit and Swoole versions and verify compatibility explicitly; coroutine test runners tend to hook PHPUnit internals and are sensitive to major-version upgrades.
- The work is scoped as a time-boxed spike on the slowest 2–3 test classes with a numeric go/no-go gate.
Look elsewhere when:
- Swoole cannot be added to developer machines or CI (extension builds, Alpine/musl images, shared hosting parity).
- Tests are CPU-bound, or the slowness comes from bootstrapping, autoloading, or container compilation — process sharding or opcache/preloading is the better lever.
- The suite depends on global state, singletons, or a shared DB transaction per test; concurrency will surface as intermittent, hard-to-reproduce failures.
- You need vendor support, an SLA, or a documented upgrade path. Twelve stars and a single maintainer means you are effectively self-supporting; budget for the possibility of forking or replacing it.
- A cheaper fix exists: replacing real sleeps with framework fakes is usually a smaller, safer, permanent change.
Assessment: treat as an experimental, opt-in tool for a bounded subset of tests, not a suite-wide default. Low stars and a 2026 release date are signals of immaturity, not disqualifiers — but they cap the blast radius you should accept.
How to Pitch It (Stakeholders)
For executives: Our test suite's slowest tests are slow because they wait — on retry backoff, rate limits, and network calls. counit is a small open-source add-on that lets those waits overlap instead of running one after another, using Swoole, a runtime we already trust in production. We are not buying anything; the license cost is zero. The proposal is a two-sprint pilot on our ten slowest test classes with a hard gate: if p95 runtime does not drop materially and flakiness does not rise, we stop and keep the status quo. Expected upside is faster feedback and lower CI spend; expected downside is contained to a handful of test files.
For engineering: It runs time/IO-bound tests concurrently inside a single PHP process via Swoole coroutines, rather than forking like ParaTest — so it sidesteps process-startup and memory overhead, but it also means your tests must be coroutine-safe. The pilot will require per-coroutine DB connections, no shared statics, and explicit version pinning of PHPUnit and Swoole. We will measure runtime, flaky rate, and upgrade friction before recommending anything beyond opt-in usage. Anyone whose tests are slow purely because of real sleep() calls should first check whether Sleep::fake() or a fake HTTP client removes the wait entirely — that is the preferred fix; this package is for the cases where it cannot be.
Recommendation: Approve a scoped pilot, not adoption. Success looks like a documented 30%+ reduction on targeted slow tests with flat flakiness; anything less, we take the refactoring lessons and drop the dependency.