tourze / phpunit-workerman
Workerman PHPUnit Support
Installs: 1
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/tourze/phpunit-workerman
Requires
- ext-sockets: *
- symfony/dependency-injection: ^7.3
- symfony/framework-bundle: ^7.3
- symfony/yaml: ^7.3
- workerman/workerman: ^5.1
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.5
- tourze/phpunit-base: 1.*
This package is auto-updated.
Last update: 2025-10-31 07:50:13 UTC
README
专为 Workerman 应用设计的 PHPUnit 测试框架,解决异步、事件驱动应用的测试难题。
目录
核心特性
主要功能
- 事件循环模拟 - 提供完全可控的事件循环和时间控制
- 异步操作测试 - 支持定时器、延迟操作和回调测试
- 连接模拟 - 完整的 TCP 连接生命周期模拟
- Worker 管理 - 创建、启动和管理 Worker 实例
- 专用断言 - 针对 Workerman 特性的断言方法
解决的问题
- 异步操作测试
- 事件循环时间控制
- 网络连接模拟
- 多进程 Worker 测试
- 定时器功能验证
安装
系统要求
- PHP 8.1 或更高版本
- ext-sockets 扩展
依赖项
- workerman/workerman ^5.1
- phpunit/phpunit ^10.0 (开发依赖)
安装命令
composer require --dev tourze/phpunit-workerman
快速开始
基础 Worker 测试
<?php use Tourze\PHPUnitWorkerman\Core\WorkermanTestCase; use Workerman\Worker; class MyWorkerTest extends WorkermanTestCase { public function testBasicWorker(): void { // 创建测试 Worker $worker = $this->createWorker('tcp://127.0.0.1:8080'); $messageReceived = false; $worker->onMessage = function ($connection, $data) use (&$messageReceived) { $messageReceived = true; $connection->send('echo: ' . $data); }; // 启动 Worker $this->startWorker($worker); // 模拟发送数据 $this->sendDataToWorker($worker, 'hello'); // 验证结果 $this->assertTrue($messageReceived); } }
定时器测试
<?php use Tourze\PHPUnitWorkerman\Core\AsyncTestCase; use Workerman\Timer; class TimerTest extends AsyncTestCase { public function testTimer(): void { $executed = false; // 创建定时器 Timer::add(0.5, function () use (&$executed) { $executed = true; }, [], false); // 快进时间 $this->advanceTime(0.6); // 验证定时器执行 $this->assertTrue($executed); } public function testRepeatingTimer(): void { $count = 0; Timer::add(0.1, function () use (&$count) { $count++; }, [], true); // 快进 1 秒,应该执行 10 次 $this->advanceTime(1.0); $this->assertEquals(10, $count); } }
连接测试
<?php use Tourze\PHPUnitWorkerman\Core\WorkermanTestCase; use Workerman\Connection\TcpConnection; class ConnectionTest extends WorkermanTestCase { public function testConnection(): void { $worker = $this->createWorker(); $events = []; $worker->onConnect = function ($connection) use (&$events) { $events[] = 'connected'; }; $worker->onMessage = function ($connection, $data) use (&$events) { $events[] = "message: $data"; }; $this->startWorker($worker); // 模拟连接 $connection = $this->createMockConnection($worker); $worker->onConnect($connection); // 模拟消息 $this->sendDataToWorker($worker, 'test'); $this->assertEquals(['connected', 'message: test'], $events); } }
核心 API
测试基类
WorkermanTestCase
用于一般的 Workerman 应用测试,提供 Worker 管理和连接模拟。
abstract class WorkermanTestCase extends TestCase { // 创建测试 Worker protected function createWorker(string $socketName = ''): Worker; // 启动 Worker protected function startWorker(Worker $worker): void; // 模拟发送数据到 Worker protected function sendDataToWorker(Worker $worker, string $data): void; // 时间快进 protected function fastForward(float $seconds): void; // 等待条件满足 protected function waitFor(callable $condition, float $timeout = 5.0): void; }
AsyncTestCase
专门用于异步操作测试
abstract class AsyncTestCase extends TestCase { // 时间推进 protected function advanceTime(float $seconds): void; // 等待直到条件满足 protected function waitUntil(callable $condition, float $timeout = 5.0): void; // 运行异步操作 protected function runAsync(callable $asyncOperation, float $timeout = 5.0); // 并行运行多个异步操作 protected function runAsyncParallel(array $operations, float $timeout = 5.0): array; }
模拟组件
MockEventLoop
模拟事件循环
class MockEventLoop implements EventInterface { // 时间快进 public function fastForward(float $seconds): void; // 触发事件 public function triggerRead($stream): void; public function triggerWrite($stream): void; public function triggerSignal(int $signal): void; // 状态查询 public function getCurrentTime(): float; public function getTimers(): array; public function hasReadEvents(): bool; }
Trait 组件
TimeControl
时间控制相关功能
trait TimeControl { protected function fastForward(float $seconds): void; protected function fastForwardToNextTimer(): bool; protected function executeAllPendingTimers(float $maxTime = 3600.0): int; protected function setCurrentTime(float $time): void; protected function getCurrentTime(): float; }
AsyncAssertions
异步操作断言
trait AsyncAssertions { protected function assertAsyncCallbackCalled(callable $trigger, float $timeout = 5.0): void; protected function assertAsyncCallbackCalledTimes(int $expectedCount, callable $trigger): void; protected function assertAsyncResult($expectedValue, callable $trigger): void; protected function waitForCondition(callable $condition, float $timeout = 5.0): void; }
ConnectionMocking
连接模拟功能
trait ConnectionMocking { protected function createMockConnection(?Worker $worker = null, string $remoteAddress = '127.0.0.1:12345'): TcpConnection; protected function mockConnectionSend(TcpConnection $connection, string $data): bool; protected function mockConnectionReceive(TcpConnection $connection, string $data): void; protected function mockConnectionClose(TcpConnection $connection): void; protected function assertConnectionStatus(TcpConnection $connection, int $expectedStatus): void; }
高级用法
复杂异步流程测试
public function testComplexAsyncFlow(): void { $results = []; // 模拟复杂异步操作链 $this->runAsync(function ($resolve, $reject) use (&$results) { Timer::add(0.1, function () use (&$results, $resolve) { $results[] = 'step1'; Timer::add(0.2, function () use (&$results, $resolve) { $results[] = 'step2'; Timer::add(0.3, function () use (&$results, $resolve) { $results[] = 'step3'; $resolve($results); }, [], false); }, [], false); }, [], false); }); $this->assertEquals(['step1', 'step2', 'step3'], $results); }
协议测试
public function testHttpProtocol(): void { $worker = $this->createWorker('tcp://127.0.0.1:8080'); $worker->protocol = \Workerman\Protocols\Http::class; $response = null; $worker->onMessage = function ($connection, $request) use (&$response) { $response = $request; $connection->send("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nHello World"); }; $this->startWorker($worker); // 发送 HTTP 请求 $httpRequest = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"; $this->sendDataToWorker($worker, $httpRequest); $this->assertNotNull($response); $this->assertStringContainsString('GET /', (string)$response); }
高并发连接测试
public function testHighConcurrency(): void { $worker = $this->createWorker(); $connectionCount = 0; $worker->onConnect = function () use (&$connectionCount) { $connectionCount++; }; // 创建1000个并发连接 $connections = $this->createMassConnections($worker, 1000); $this->assertEquals(1000, $connectionCount); $this->assertCount(1000, $connections); }
错误处理测试
public function testErrorHandling(): void { $worker = $this->createWorker(); $errorHandled = false; $worker->onError = function ($connection, $code, $msg) use (&$errorHandled) { $errorHandled = true; $this->assertEquals(500, $code); $this->assertEquals('测试错误', $msg); }; $worker->onMessage = function ($connection, $data) { if ($data === 'error') { throw new \RuntimeException('测试错误'); } }; $this->startWorker($worker); // 触发错误 $this->sendDataToWorker($worker, 'error'); $this->assertTrue($errorHandled); }
最佳实践
1. 测试初始化
正确设置和清理测试环境
class MyTest extends WorkermanTestCase { protected function setUp(): void { parent::setUp(); // 必须调用父类方法 } protected function tearDown(): void { parent::tearDown(); // 必须调用父类方法 } }
2. 异步操作超时
为异步操作设置合理的超时时间
$this->waitFor(fn() => $condition, 5.0); // 5秒超时 $this->runAsync($operation, 10.0); // 10秒超时
3. 时间控制
使用时间快进而不是真实等待
// 推荐:瞬间完成 $this->fastForward(2.0); // 不推荐:真实等待 sleep(2);
4. 连接清理
及时清理连接和资源
$connection = $this->createMockConnection($worker); // ... 测试逻辑 $this->mockConnectionClose($connection); // 测试结束前清理
常见问题
调试相关
Q: 定时器测试失败怎么办?
A: 使用 fastForward() 方法而不是真实等待
Q: 连接状态异常?
A: 确保使用 mockConnectionClose() 等方法正确管理连接生命周期
Q: 测试运行超时? A: 检查异步操作是否正确完成,确保没有无限循环
Q: 测试环境初始化失败?
A: 确保测试类正确继承并调用 parent::setUp() 和 parent::tearDown()
性能优化
如果测试较慢,可以尝试:
// 减少 Worker 数量 $this->createWorker(); // 而不是多个 // 调试定时器状态 $timerCount = $this->getPendingTimerCount(); $timers = $this->eventLoop->getTimers();
贡献指南
欢迎提交 Issue 和 Pull Request 来改进这个测试框架。
开发环境
git clone <repository> cd phpunit-workerman composer install vendor/bin/phpunit
代码规范
遵循 PSR-12 编码标准
许可证
MIT 许可证
相关资源
这个测试框架让您能够轻松测试 Workerman 应用中的异步操作、事件处理和网络通信功能。