Download the PHP package deminy/counit without Composer

On this page you can find all versions of the php package deminy/counit. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package counit

counit: to run time/IO related unit tests faster using Swoole

Library Status Latest Stable Version Latest Unstable Version License

This package helps to run time/IO related unit tests (e.g., sleep function calls, database queries, API calls, etc) faster using Swoole.

Table of Contents

How Does It Work

Package counit allows running multiple time/IO related tests concurrently within a single PHP process using Swoole. Counit is compatible with PHPUnit, which means:

  1. Test cases can be written in the same way as those for PHPUnit.
  2. Test cases can run directly under PHPUnit.

A typical test case of counit looks like this:

Comparing to PHPUnit, counit could make your test cases faster. Here is a comparison when running the same test suite using PHPUnit and counit for a real project. In the test suite, many tests make calls to method \Deminy\Counit\Counit::sleep() to wait something to happen (e.g., wait data to expire).

  # of Tests # of Assertions Time to Finish
counit (without Swoole), or PHPUnit 44 1148 9 minutes and 18 seconds
counit (with Swoole enabled) 19 seconds

Installation

The package can be installed using Composer:

Or, in your composer.json file, make sure to have package deminy/counit included:

Please pick the counit version matching the version of PHPUnit used in your project:

counit PHPUnit PHP
^1.1 ~13.0 >= 8.4.1
^1.1 ~12.5.24 >= 8.3
^0.3 ~8.0, ~9.0 >= 7.2

Use "counit" in Your Project

Register the PHPUnit Extension

Without the extension registered, PHPUnit prints its summary while your tests' coroutines are still running, so the run's reported numbers describe an unfinished run. Every compatibility guarantee in Compatibility with PHPUnit — reported time, assertion totals, late failures, skips and risky verdicts — assumes it is registered. Register it unless you have a specific reason not to.

The syntax depends on your PHPUnit version. For PHPUnit 10 and above (counit ^1.1):

For PHPUnit 8 and 9 (counit ^0.3), where the class implements the older hook interfaces:

A run that creates its first coroutine without the extension registered says so once on STDERR, so the failure mode below is not a silent one:

What goes wrong without it

The extension is a reporting fix, not a performance trade-off: it waits for coroutines that were going to run anyway, so it does not slow a suite down measurably (~0.01s on the 358-test suite above).

Examples

Folder ./tests/unit/automatic and ./tests/unit/manual contain some sample tests, where we have following time-related tests included:

Setup Test Environment

To run the sample tests, please start the Docker containers and install Composer packages first:

There are five containers started: a PHP container, a Swoole container, a Redis container, a MySQL container, and a web server. The PHP container doesn't have the Swoole extension installed, while the Swoole container has it installed and enabled.

As said previously, test cases can be written in the same way as those for PHPUnit. However, to run time/IO related tests faster with counit, we need to make some adjustments when writing those test cases; these adjustments can be made using two different approaches.

The Automatic Approach (recommended)

In this approach (previously called the "global" style), each test case runs in a separate coroutine automatically. Use it for every test class you can — it's the simplest and least error-prone way to get counit's speedup, and needs no ongoing discipline once adopted. The only reason not to is if a test class must extend something other than PHPUnit\Framework\TestCase already (PHP allows only one parent class) — see The Manual Approach below for that case.

For test cases written using this approach, the only change to make on your existing test cases is to use class Deminy\Counit\TestCase instead of PHPUnit\Framework\TestCase as the base class.

A typical test case of the automatic approach looks like this:

When customized method setUpBeforeClass() and tearDownAfterClass() are defined in the test cases, please make sure to call their parent methods accordingly in these customized methods.

With the PHPUnit extension registered, the total # of assertions reported at the end of a run matches PHPUnit exactly, and the per-testcase counts in the JUnit XML report (--log-junit) are corrected as well — exact whenever counit can observe the test's yields (sleep()/usleep() calls in a namespaced test class, and Counit::sleep()). An assertion performed after a yield counit cannot observe (e.g. hooked network IO) goes missing from its own test's JUnit count — but is never added to another test's. See Compatibility with PHPUnit.

To find more tests written using this approach, please check tests under folder ./tests/unit/automatic (test suite "automatic").

The Manual Approach

In this approach (previously called the "case by case" style), you make changes directly on a test case to make it work asynchronously, without changing which class it extends.

Reach for this only when the automatic approach isn't an option. PHP allows a class to extend only one parent, so if your test classes must already extend something else — a framework's own base class (e.g. Laravel's Illuminate\Foundation\Testing\TestCase, Symfony's KernelTestCase/WebTestCase) or a shared internal base class your project already relies on — you can't also extend Deminy\Counit\TestCase. The manual approach lets you speed up individual slow test methods with that extends clause left untouched. It also makes trialing counit on a handful of tests lower-risk than committing a whole class hierarchy to the automatic approach up front.

It comes with real trade-offs the automatic approach doesn't have: forgetting to wrap a slow test body doesn't error, it just silently leaves that one test blocking; calling PHP's native sleep() instead of Counit::sleep() inside a coroutine blocks the whole scheduler, not just that test; and the optional assertion-count parameter below is bookkeeping you have to get right yourself. Prefer the automatic approach whenever your test class can use it.

If what you actually want is several of your own coroutines running concurrently against each other — testing a mutex, a queue, or other coroutine-native code directly, rather than speeding up one blocking call — see Deminy\Counit\CoroutineGroup instead; it's a dedicated, nesting-safe primitive for that, usable from either approach, including from inside a manual-approach Counit::create() call.

For test cases written using this approach, we need to use class Deminy\Counit\Counit accordingly in the test cases where we need to wait for PHP execution or to perform IO operations. Typically, following method calls will be used:

A typical test case of the manual approach looks like this:

In case you need to suppress warning message "This test did not perform any assertions" or to make the number of assertions match, you can include a 2nd parameter when creating the new coroutine:

The 2nd parameter is a request rather than a command: for a test that declares it performs no assertions (through attribute #[DoesNotPerformAssertions] or method expectNotToPerformAssertions()), Counit::create() declines the credit — crediting such a test would make PHPUnit report it as risky.

To find more tests written using this approach, please check tests under folder ./tests/unit/manual (test suite "manual").

Comparisons

Both approaches perform identically — the choice between them is about which one you're able to use (see docs/comparisons.md has the proof: benchmarks running counit's own sample test suites under every combination of PHPUnit/counit and with/without Swoole.

Compatibility with PHPUnit

Counit is designed as a drop-in companion to PHPUnit, not a replacement. In short:

That leaves one combination to document: running tests under the counit runner with Swoole enabled — the fast, concurrent mode this package exists for. docs/compatibility.md covers it in full: a matrix of compatible features, a matrix of incompatible ones (each with a Counit 0.x reference column for the PHPUnit ~8.0/~9.0 maintenance line), and the per-feature notes behind every ⚠️/❌ entry.

Testing Coroutine-Native Code Directly

Everything above speeds up a test that makes one blocking call — sleep(), a database query, an HTTP request — by letting it yield while other tests keep running. A different kind of test needs several of its own coroutines to run concurrently against each other — one exercising a mutex, a queue, or any other coroutine-native code directly — which needs a different tool. docs/coroutine-native-testing.md covers Deminy\Counit\CoroutineGroup, a nesting-safe, timeout-capable substitute for Swoole\Coroutine\Scheduler, including how sequential calls to it interact with each other.

Additional Notes

Since this package allows running multiple tests simultaneously, we should not use same resources in different tests; otherwise, racing conditions could happen. For example, if multiple tests use the same Redis key, some of them could fail occasionally. In this case, we should use different Redis keys in different test cases. Method \Deminy\Counit\Helper::getNewKey() and \Deminy\Counit\Helper::getNewKeys() can be used to generate random and unique test keys.

The package works best for tests that have function call sleep() in use; It can also help to run some IO related tests faster, with limitations apply. Here is a list of limitations of this package:

Local Development

Docker images used to run the sample tests are built locally via docker-compose.yml, which builds the php and swoole services from the Dockerfiles under ./dockerfiles. See Setup Test Environment.

Alternatives

This package allows to use Swoole to run multiple time/IO related tests without multiprocessing, which means all tests can run within a single PHP process. To understand how exactly it works, I'd recommend checking this free online talk: CSP Programming in PHP (and here are the slides).

In the PHP ecosystem, there are other options to run unit tests in parallel, most end up using multiprocessing:

License

MIT license.


All versions of counit with dependencies

PHP Build Version
Package Version
Requires php Version >=8.3
phpunit/phpunit Version ~12.5.24 || ~13.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package deminy/counit contains the following files

Loading the files please wait ...