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.
php -m | grep swoole). CoUnit is a test-time dependency, so install it with composer require --dev deminy/counit.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.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.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.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.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.setUpBeforeClass, then keep per-coroutine state local. Prefer per-coroutine DB connections or transactional cleanup keyed to the coroutine, not a single shared connection.@dataProvider with concurrency: multiple scenarios that each involve IO can be dispatched together, and per-case assertions stay independent.--filter so you can attach a debugger or add Coroutine::stats() logging without the noise of the full suite.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).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.--process-isolation (it defeats coroutine batching) and Xdebug coverage (it serializes execution and can erase the speedup).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.How can I help you explore Laravel packages today?