friendsofhyperf / co-phpunit
The Co-PHPUnit component for Hyperf.
Fund package maintenance!
huangdijia
hdj.me/sponsors
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
pkg:composer/friendsofhyperf/co-phpunit
Requires
- hyperf/coordinator: ~3.1.0
- phpunit/phpunit: ^10.0 || ^11.0 || ^12.0
This package is auto-updated.
Last update: 2025-10-27 06:33:37 UTC
README
A PHPUnit extension that enables tests to run inside Swoole coroutines, specifically designed for testing Hyperf applications and other Swoole-based frameworks.
Installation
composer require friendsofhyperf/co-phpunit --dev
Why Co-PHPUnit?
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:
- Coroutine context not being available
- Timers and event loops not working correctly
- Coordinator pattern failures
- Database connection pool issues
Co-PHPUnit solves these problems by automatically wrapping test execution in a Swoole coroutine context when needed.
Usage
Basic Usage
Simply use the RunTestsInCoroutine trait in your test class:
<?php namespace Your\Namespace\Tests; use FriendsOfHyperf\CoPHPUnit\Concerns\RunTestsInCoroutine; use PHPUnit\Framework\TestCase; class YourTest extends TestCase { use RunTestsInCoroutine; public function testSomething() { // Your test code here // This will automatically run inside a Swoole coroutine } }
Disabling Coroutine for Specific Tests
If you need to disable coroutine execution for a specific test class, set the $enableCoroutine property to false:
<?php namespace Your\Namespace\Tests; use FriendsOfHyperf\CoPHPUnit\Concerns\RunTestsInCoroutine; use PHPUnit\Framework\TestCase; class YourTest extends TestCase { use RunTestsInCoroutine; protected bool $enableCoroutine = false; public function testSomething() { // This test will run in normal synchronous mode } }
How It Works
The RunTestsInCoroutine trait overrides PHPUnit's runBare() method to:
- Check Prerequisites: Verifies that the Swoole extension is loaded and not already in a coroutine context
- Create Coroutine Context: Wraps test execution in
Swoole\Coroutine\run() - Exception Handling: Properly captures and re-throws exceptions from within the coroutine
- Cleanup: Clears all timers and resumes coordinator on test completion
- Fallback: If conditions aren't met, falls back to normal test execution
PHPUnit Patch
The 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 applied automatically when the package is autoloaded.
Requirements
- PHP >= 8.0
- PHPUnit >= 10.0
- Swoole extension (when running tests in coroutine mode)
- Hyperf >= 3.1 (for coordinator functionality)
Configuration
Composer Autoload
The package automatically registers its autoload files in composer.json:
{
"autoload-dev": {
"psr-4": {
"Your\\Tests\\": "tests/"
},
"files": [
"vendor/friendsofhyperf/co-phpunit/phpunit-patch.php"
]
}
}
PHPUnit Configuration
No special PHPUnit configuration is required. The package works seamlessly with your existing phpunit.xml configuration.
Best Practices
- Use for Integration Tests: This is particularly useful for integration tests that interact with Hyperf's coroutine-aware components
- Selective Enablement: Not all tests need to run in coroutines. Use
$enableCoroutine = falsefor unit tests that don't require coroutine context - Test Isolation: The package automatically cleans up timers and coordinator state between tests
- Performance: Tests running in coroutines may have slightly different performance characteristics
Example: Testing Hyperf Services
<?php namespace App\Tests; use FriendsOfHyperf\CoPHPUnit\Concerns\RunTestsInCoroutine; use Hyperf\Context\ApplicationContext; use PHPUnit\Framework\TestCase; class ServiceTest extends TestCase { use RunTestsInCoroutine; public function testServiceWithCoroutineContext() { // Get service from container $service = ApplicationContext::getContainer()->get(YourService::class); // Test methods that use coroutine context $result = $service->asyncOperation(); $this->assertNotNull($result); } public function testDatabaseConnection() { // Test database operations that require connection pool $result = Db::table('users')->first(); $this->assertIsArray($result); } }
Troubleshooting
Tests Hang or Timeout
If tests hang, ensure that:
- All async operations are properly awaited
- No infinite loops exist in coroutine callbacks
- Timers are cleared in test teardown
"Call to a member function on null"
This usually indicates that coroutine context is not available. Ensure:
- Swoole extension is installed and enabled
- The
RunTestsInCoroutinetrait is included $enableCoroutineis set totrue
PHPUnit Version Compatibility
The package supports PHPUnit 10.x, 11.x, and 12.x. Ensure your PHPUnit version is compatible.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
- Issues: GitHub Issues
- Documentation: Hyperf Fans
- Pull Requests: GitHub Pull Requests
License
This package is open-sourced software licensed under the MIT license.