Skip to content

Commit 418921b

Browse files
authored
Add missing documentation for co-phpunit and command-benchmark components (#978)
1 parent b84783e commit 418921b

File tree

14 files changed

+1250
-0
lines changed

14 files changed

+1250
-0
lines changed

docs/.vitepress/src/en/sidebars.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ const sidebar:DefaultTheme.Sidebar = {
1313
text: 'Cache',
1414
link: '/en/components/cache.md'
1515
},
16+
{
17+
text: 'Co-PHPUnit',
18+
link: '/en/components/co-phpunit.md'
19+
},
20+
{
21+
text: 'Command Benchmark',
22+
link: '/en/components/command-benchmark.md'
23+
},
1624
{
1725
text: 'Command Signals',
1826
link: '/en/components/command-signals.md'

docs/.vitepress/src/zh-cn/sidebars.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ const sidebar:DefaultTheme.Sidebar = {
2626
text: 'Cache',
2727
link: '/zh-cn/components/cache.md'
2828
},
29+
{
30+
text: 'Co-PHPUnit',
31+
link: '/zh-cn/components/co-phpunit.md'
32+
},
33+
{
34+
text: 'Command Benchmark',
35+
link: '/zh-cn/components/command-benchmark.md'
36+
},
2937
{
3038
text: 'Command Signals',
3139
link: '/zh-cn/components/command-signals.md'

docs/.vitepress/src/zh-hk/sidebars.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ const sidebar:DefaultTheme.Sidebar = {
2626
text: 'Cache',
2727
link: '/zh-hk/components/cache.md'
2828
},
29+
{
30+
text: 'Co-PHPUnit',
31+
link: '/zh-hk/components/co-phpunit.md'
32+
},
33+
{
34+
text: 'Command Benchmark',
35+
link: '/zh-hk/components/command-benchmark.md'
36+
},
2937
{
3038
text: 'Command Signals',
3139
link: '/zh-hk/components/command-signals.md'

docs/.vitepress/src/zh-tw/sidebars.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ const sidebar:DefaultTheme.Sidebar = {
2626
text: 'Cache',
2727
link: '/zh-tw/components/cache.md'
2828
},
29+
{
30+
text: 'Co-PHPUnit',
31+
link: '/zh-tw/components/co-phpunit.md'
32+
},
33+
{
34+
text: 'Command Benchmark',
35+
link: '/zh-tw/components/command-benchmark.md'
36+
},
2937
{
3038
text: 'Command Signals',
3139
link: '/zh-tw/components/command-signals.md'

docs/en/components/co-phpunit.md

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# Co-PHPUnit
2+
3+
A PHPUnit extension that enables tests to run within Swoole coroutines, specifically designed for testing Hyperf applications and other Swoole-based frameworks.
4+
5+
## Installation
6+
7+
```bash
8+
composer require friendsofhyperf/co-phpunit --dev
9+
```
10+
11+
## Why Co-PHPUnit?
12+
13+
When testing Hyperf applications, many components rely on Swoole's coroutine context to function properly. Running tests in a traditional synchronous environment can lead to issues such as:
14+
15+
- Coroutine context being unavailable
16+
- Timers and event loops not working correctly
17+
- Coordinator pattern failures
18+
- Database connection pool problems
19+
20+
Co-PHPUnit addresses these issues by automatically wrapping test execution within Swoole coroutine contexts when needed.
21+
22+
## Usage
23+
24+
### Basic Usage
25+
26+
Simply use the `RunTestsInCoroutine` trait in your test class:
27+
28+
```php
29+
<?php
30+
31+
namespace Your\Namespace\Tests;
32+
33+
use FriendsOfHyperf\CoPHPUnit\Concerns\RunTestsInCoroutine;
34+
use PHPUnit\Framework\TestCase;
35+
36+
class YourTest extends TestCase
37+
{
38+
use RunTestsInCoroutine;
39+
40+
public function testSomething()
41+
{
42+
// Your test code
43+
// This will automatically run within a Swoole coroutine
44+
}
45+
}
46+
```
47+
48+
### Disabling Coroutine for Specific Tests
49+
50+
If you need to disable coroutine execution for a particular test class, set the `$enableCoroutine` property to `false`:
51+
52+
```php
53+
<?php
54+
55+
namespace Your\Namespace\Tests;
56+
57+
use FriendsOfHyperf\CoPHPUnit\Concerns\RunTestsInCoroutine;
58+
use PHPUnit\Framework\TestCase;
59+
60+
class YourTest extends TestCase
61+
{
62+
use RunTestsInCoroutine;
63+
64+
protected bool $enableCoroutine = false;
65+
66+
public function testSomething()
67+
{
68+
// This test will run in normal synchronous mode
69+
}
70+
}
71+
```
72+
73+
## How It Works
74+
75+
The `RunTestsInCoroutine` trait overrides PHPUnit's `runBare()` method to:
76+
77+
1. **Check Prerequisites**: Verify that the Swoole extension is loaded and not already in a coroutine context
78+
2. **Create Coroutine Context**: Wrap test execution within `Swoole\Coroutine\run()`
79+
3. **Exception Handling**: Properly catch and re-throw exceptions from within coroutines
80+
4. **Cleanup**: Clear all timers and restore the coordinator when tests complete
81+
5. **Fallback**: Fall back to normal test execution if conditions aren't met
82+
83+
### PHPUnit Patch
84+
85+
This package includes a `phpunit-patch.php` file that automatically removes the `final` keyword from PHPUnit's `TestCase::runBare()` method, allowing the trait to override it. This patch is automatically applied when the package autoloads.
86+
87+
## Requirements
88+
89+
- PHP >= 8.0
90+
- PHPUnit >= 10.0
91+
- Swoole extension (when running tests in coroutine mode)
92+
- Hyperf >= 3.1 (for coordinator functionality)
93+
94+
## Configuration
95+
96+
### Composer Autoload
97+
98+
The package automatically registers its autoload files in composer.json:
99+
100+
```json
101+
{
102+
"autoload-dev": {
103+
"psr-4": {
104+
"Your\\Tests\\": "tests/"
105+
},
106+
"files": [
107+
"vendor/friendsofhyperf/co-phpunit/phpunit-patch.php"
108+
]
109+
}
110+
}
111+
```
112+
113+
### PHPUnit Configuration
114+
115+
No special PHPUnit configuration is required. The package works seamlessly with your existing `phpunit.xml` configuration.
116+
117+
## Best Practices
118+
119+
1. **Use for Integration Tests**: This is particularly useful for integration tests that interact with Hyperf's coroutine-aware components
120+
2. **Enable Selectively**: Not all tests need to run in coroutines. Use `$enableCoroutine = false` for unit tests that don't require coroutine context
121+
3. **Test Isolation**: The package automatically cleans up timers and coordinator state between tests
122+
4. **Performance**: Tests running in coroutines may have slightly different performance characteristics
123+
124+
## Example: Testing Hyperf Services
125+
126+
```php
127+
<?php
128+
129+
namespace App\Tests;
130+
131+
use FriendsOfHyperf\CoPHPUnit\Concerns\RunTestsInCoroutine;
132+
use Hyperf\Context\ApplicationContext;
133+
use PHPUnit\Framework\TestCase;
134+
135+
class ServiceTest extends TestCase
136+
{
137+
use RunTestsInCoroutine;
138+
139+
public function testServiceWithCoroutineContext()
140+
{
141+
// Get service from container
142+
$service = ApplicationContext::getContainer()->get(YourService::class);
143+
144+
// Test methods that use coroutine context
145+
$result = $service->asyncOperation();
146+
147+
$this->assertNotNull($result);
148+
}
149+
150+
public function testDatabaseConnection()
151+
{
152+
// Test database operations that require connection pools
153+
$result = Db::table('users')->first();
154+
155+
$this->assertIsArray($result);
156+
}
157+
}
158+
```
159+
160+
## Troubleshooting
161+
162+
### Tests Hanging or Timing Out
163+
164+
If tests hang, ensure:
165+
- All async operations are properly awaited
166+
- No infinite loops exist in coroutine callbacks
167+
- Timers are cleared during test teardown
168+
169+
### "Call to a member function on null"
170+
171+
This typically indicates coroutine context is unavailable. Ensure:
172+
- Swoole extension is installed and enabled
173+
- The `RunTestsInCoroutine` trait is included
174+
- `$enableCoroutine` is set to `true`
175+
176+
### PHPUnit Version Compatibility
177+
178+
This package supports PHPUnit 10.x, 11.x, and 12.x. Make sure your PHPUnit version is compatible.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Command Benchmark
2+
3+
A benchmarking component for Hyperf commands, forked from [christophrumpel/artisan-benchmark](https://github.com/christophrumpel/artisan-benchmark).
4+
5+
## Installation
6+
7+
```shell
8+
composer require friendsofhyperf/command-benchmark
9+
```
10+
11+
## Introduction
12+
13+
The Command Benchmark component provides performance benchmarking capabilities for Hyperf commands. It automatically collects and displays performance metrics for command execution, including:
14+
15+
- **Execution Time**: The time required for the command to run
16+
- **Memory Usage**: Memory consumed during command execution
17+
- **Database Query Count**: Number of SQL queries executed during command execution
18+
19+
## Usage
20+
21+
This component automatically adds the `--enable-benchmark` option to all Hyperf commands through AOP (Aspect-Oriented Programming).
22+
23+
### Enabling Benchmarking
24+
25+
Simply add the `--enable-benchmark` option when running any command to enable benchmarking:
26+
27+
```shell
28+
php bin/hyperf.php your:command --enable-benchmark
29+
```
30+
31+
### Output Example
32+
33+
After command execution completes, benchmark results will be displayed at the end of the output:
34+
35+
```
36+
⚡ TIME: 2.5s MEM: 15.23MB SQL: 42
37+
```
38+
39+
Metric explanations:
40+
- **TIME**: Execution time (milliseconds, seconds, or minutes)
41+
- **MEM**: Memory usage (MB)
42+
- **SQL**: Number of SQL queries executed
43+
44+
## How It Works
45+
46+
This component uses Hyperf's AOP functionality to intercept command construction and execution:
47+
48+
1. **Construction Phase**:
49+
- Records start time and memory usage
50+
- Registers database query event listeners
51+
- Adds the `--enable-benchmark` option to the command
52+
53+
2. **Execution Phase**:
54+
- If the `--enable-benchmark` option is enabled
55+
- Calculates execution time, memory usage, and query count
56+
- Formats and displays benchmark results
57+
58+
3. **Result Display**:
59+
- Displays metrics using colored output
60+
- Automatically formats time (milliseconds, seconds, minutes)
61+
- Shows results at the end of command output
62+
63+
## Configuration
64+
65+
This component requires no additional configuration and is ready to use after installation. It automatically registers with the Hyperf container.
66+
67+
## Technical Details
68+
69+
### AOP Aspect
70+
71+
The component intercepts the following methods of the `Hyperf\Command\Command` class through the `CommandAspect` aspect class:
72+
- `__construct`: Initializes performance metric collection
73+
- `execute`: Displays benchmark results after execution completes
74+
75+
### Performance Metrics
76+
77+
- **Execution Time**: Measured using `microtime(true)`
78+
- **Memory Usage**: Measured using `memory_get_usage()`
79+
- **Query Count**: Counted by listening to `QueryExecuted` events
80+
81+
### Time Formatting
82+
83+
Time is automatically formatted with appropriate units based on execution duration:
84+
- Less than 1 second: Displayed in milliseconds (e.g., `250ms`)
85+
- 1 second to 60 seconds: Displayed in seconds (e.g., `2.5s`)
86+
- More than 60 seconds: Displayed in minutes and seconds (e.g., `2m 30s`)
87+
88+
## Examples
89+
90+
### Testing Data Import Command
91+
92+
```shell
93+
php bin/hyperf.php import:users --enable-benchmark
94+
```
95+
96+
Output:
97+
```
98+
Importing users...
99+
100 users imported successfully.
100+
101+
⚡ TIME: 5.23s MEM: 28.45MB SQL: 150
102+
```
103+
104+
### Testing Cache Clear Command
105+
106+
```shell
107+
php bin/hyperf.php cache:clear --enable-benchmark
108+
```
109+
110+
Output:
111+
```
112+
Cache cleared successfully.
113+
114+
⚡ TIME: 120ms MEM: 2.15MB SQL: 0
115+
```
116+
117+
## Notes
118+
119+
1. Benchmarking introduces slight performance overhead; recommended for development and debugging only
120+
2. SQL query statistics include all queries executed through the Hyperf database component
121+
3. Memory usage is a relative value, representing the increase in memory usage during command execution
122+
123+
## Contact
124+
125+
- [Twitter](https://twitter.com/huangdijia)
126+
- [Gmail](mailto:[email protected])

0 commit comments

Comments
 (0)