Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 0
Testing
Because the runtime is built from small, injected parts, you can test handlers and workers without standing up a real broker.
A handler is a plain object — call handle() with a ReceivedMessage you build
from an envelope:
useBabelQueue\Codec\EnvelopeCodec;
useInitPHP\Queue\Message\ReceivedMessage;
$envelope = EnvelopeCodec::make('urn:babel:users:registered', ['user_id' => 42], 'emails');
$message = newReceivedMessage('emails', EnvelopeCodec::encode($envelope), $envelope, receipt: 1);
$handler = newSendWelcomeEmail();
$handler->handle($message); // assert the side effectsReceivedMessage implements BabelQueue\Contracts\InboundMessage, so it is
exactly what the handler sees in production.
The dispatcher returns an Outcome you can assert on, with no broker involved:
useInitPHP\Queue\Consumer\Dispatcher;
useInitPHP\Queue\Consumer\OutcomeKind;
useInitPHP\Queue\Routing\HandlerMap;
$handlers = (newHandlerMap())->register('urn:babel:users:registered', newSendWelcomeEmail());
$outcome = (newDispatcher($handlers))->dispatch($message);
self::assertSame(OutcomeKind::Ack, $outcome->kind);OutcomeKind is Ack, Retry, DeadLetter, Drop or Release; the Outcome
also exposes ->reason and ->exception.
Drive a real Worker against a fake ConsumerTransport. A minimal in-memory
implementation is enough — it queues payloads, hands them out on reserve(), and
records deadLetter()/release() for assertions:
useInitPHP\Queue\Consumer\Dispatcher;
useInitPHP\Queue\Consumer\Worker;
useInitPHP\Queue\Consumer\WorkerOptions;
$worker = newWorker($transport, newDispatcher($handlers), newWorkerOptions(stopWhenEmpty: true));
$transport->publish(EnvelopeCodec::encode(EnvelopeCodec::make('urn:babel:users:registered', [], 'emails')), 'emails');
$worker->run('emails'); // drains and returns (stopWhenEmpty)self::assertSame(1, $worker->processedCount());Two options make worker tests deterministic:
stopWhenEmpty: true—run()returns the moment the queue is empty, so a test never blocks.runOnce($queue)— process exactly one message and return; ideal for step-by-step assertions of the retry → dead-letter progression.
// maxAttempts: 2 — fail twice, then dead-letter:$worker->runOnce('orders'); // attempt 1 -> re-queued$worker->runOnce('orders'); // attempt 2 -> dead-letteredBecause the worker re-queues a failed message with an incremented attempts, a
fake transport that records release()/deadLetter() payloads lets you assert the
whole policy: the delays passed to release(), the final attempts, and the
dead_letter.reason in the annotated envelope.
The package's own integration tests connect to real Redis, RabbitMQ and MySQL and are skipped unless the matching environment variables are set, so they are a no-op locally and run in CI with service containers:
| Variable | Example |
|---|---|
QUEUE_TEST_REDIS_DSN | tcp://127.0.0.1:6379 |
QUEUE_TEST_AMQP_HOST (+ _PORT/_USER/_PASS) | 127.0.0.1 |
QUEUE_TEST_MYSQL_DSN (+ _USER/_PASS) | mysql:host=127.0.0.1;port=3306;dbname=queue_test |
Adopt the same pattern in your own suite when you want to exercise a real broker: gate the test on an env var and skip otherwise.
InitPHP Queue · GitHub · Packagist · BabelQueue standard · MIT License