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

Counit Laravel Package

deminy/counit

CoUnit is a lightweight unit testing framework for PHP that offers a simple API for writing assertions and running test suites. It’s a practical alternative to heavier tools for small projects and quick tests, and can be installed via Composer.

Deep Wiki
Context7

Getting Started

  1. Confirm prerequisites. You need PHP with the Swoole extension compiled/loaded (php -m | grep swoole). CoUnit is a test-time dependency, so install it with composer require --dev deminy/counit.
  2. Read first, in this order: the repository README, then the base TestCase/trait class under src/, then any phpunit.xml snippet in the docs that wires up the bootstrap or extension. Since the repo metadata is incomplete, that source reading is the authoritative reference — treat it as the API contract.
  3. Wire it in minimally. Point PHPUnit's bootstrap at the package's bootstrap (or register the extension in phpunit.xml if that's how the installed version works), then change a single slow test class from PHPUnit\Framework\TestCase to the package's base test case. Do not migrate the whole suite at once.
  4. First use case: pick the worst offender — a test that does sleep(5) to exercise a retry, or a loop of sequential HTTP/DB calls. Run it under plain PHPUnit, record the wall-clock time, then run it under CoUnit. The win comes from coroutine scheduling (sleeps yield instead of blocking; IO calls overlap) rather than from any mocking, so you should see the same assertions pass in a fraction of the time.

Implementation Patterns

  • Per-class opt-in. Keep pure-logic tests on plain PHPUnit and extend the CoUnit base class only for IO-bound suites. This limits blast radius and makes regressions easy to bisect.
  • Batch independent waits. The highest-value refactor is turning sequential loops into concurrent coroutine groups — e.g. foreach ($urls as $u) { $client->get($u); } becomes a waitGroup/go batch, or a single test that fires N requests and asserts all results. Verify that the package's base class gives you the coroutine context to do this; if not, wrap the body in Swoole\Coroutine\run() inside the test.
  • Rely on runtime hooks, not mocks. Enable coroutine hooks (Swoole\Runtime::enableCoroutine(), usually done by the package bootstrap) so sleep, usleep, stream sockets, and PDO are made non-blocking. That's what makes existing sleep()-based retry/backoff tests suddenly fast without rewriting them.
  • Shared setup, isolated work. Do expensive one-time setup (container boot, DB schema) in setUpBeforeClass, then keep per-coroutine state local. Prefer per-coroutine DB connections or transactional cleanup keyed to the coroutine, not a single shared connection.
  • Table-driven slow tests. Combine @dataProvider with concurrency: multiple scenarios that each involve IO can be dispatched together, and per-case assertions stay independent.
  • CI discipline. Add a job that runs the suite both with and without CoUnit (or compare wall time) so you notice when a test silently reverts to blocking behavior. Record durations to catch drift.
  • Debug harness. Keep a small script that runs one coroutine-heavy test under --filter so you can attach a debugger or add Coroutine::stats() logging without the noise of the full suite.

Gotchas and Tips

  • Shared global state is the #1 failure mode. PHPUnit assertions, static properties, singletons, the Laravel container, and anything else process-global are not coroutine-safe. Concurrency turns "sometimes flaky" into "always flaky." Keep concurrent tests free of shared mutable state, or serialize.
  • Hooks must be on before the first blocking call. Enabling coroutine hooks mid-run is unreliable; it must happen in the bootstrap, before any framework boot or sleep(). If a test is still slow, verify hooks are actually active for the function you're calling (e.g. curl_exec vs stream_socket_client — not every extension is hookable).
  • Hangs look like test failures. A test that never finishes usually means a coroutine blocked on a non-hooked function or a connection held open. Debug with Swoole\Coroutine::stats() / listing active coroutines, and set both PHPUnit's timeout and Swoole's coroutine limit so you get an error instead of a stuck CI job.
  • PHPUnit version matters. Extension registration and hook APIs differ across PHPUnit 9/10/11. Match the package version to your PHPUnit major, and be wary of --process-isolation (it defeats coroutine batching) and Xdebug coverage (it serializes execution and can erase the speedup).
  • DB semantics change under concurrency. Tests that mutate shared rows will race. Use transactions per coroutine where the driver supports it, or distinct fixture keys per test.
  • Time assertions need adjusting. A test asserting "this took at least 2 seconds" is exactly what this package breaks. Assert on call counts / observable behavior instead of elapsed time, or keep those specific tests on plain PHPUnit.
  • Extension points to look for: a custom base TestCase or trait that wraps setUp/tearDown in a coroutine, an overridable hook list, and a bootstrap you can layer on top of Laravel's CreatesApplication. Wrap rather than fork — subclassing the provided base class is the intended seam, and it keeps you upgradeable when the package tracks newer Swoole/PHPUnit releases.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle