zenstruck/messenger-test
Test helpers and assertions for symfony/messenger. Provides a TestTransport that intercepts and round-trips messages, lets you inspect queued items, assert counts/contents and processing states (acked/rejected), and optionally process queued messages in Kernel/Web tests.
Installation
composer require --dev zenstruck/messenger-test
Add to composer.json under require-dev if not using auto-discovery.
First Use Case Test a message handler with assertions:
use Zenstruck\MessengerTest\Assertion\AssertsMessages;
use Zenstruck\MessengerTest\Assertion\AssertsMessagesTrait;
class SendEmailHandlerTest extends TestCase
{
use AssertsMessagesTrait;
public function testHandlesSendEmailMessage()
{
$this->assertMessages([new SendEmailMessage('test@example.com')]);
// Dispatch a message
$this->dispatch(new SendEmailMessage('test@example.com'));
// Assert it was dispatched
$this->assertMessages([new SendEmailMessage('test@example.com')]);
}
}
Key Classes to Explore
AssertsMessagesTrait: Core assertions for message handling.AssertsMessages: Standalone assertion class.MessageBus: Helper for testing message buses.RetryTestTrait).Setup
Use AssertsMessagesTrait in your test class:
use Zenstruck\MessengerTest\Assertion\AssertsMessagesTrait;
class MyTest extends TestCase
{
use AssertsMessagesTrait;
}
Assert Message Dispatch
$this->assertMessages([new MyMessage('value')]);
Dispatch Messages
$this->dispatch(new MyMessage('value'));
Assert Message Handling
$this->assertMessagesHandled([new MyMessage('value')]);
RetryTestTrait to control retry behavior:
use Zenstruck\MessengerTest\Retry\RetryTestTrait;
class RetryTest extends TestCase
{
use RetryTestTrait;
public function testRetryBehavior()
{
// Disable retries globally
$this->disableRetries();
// Or enable retries with custom max attempts
$this->enableRetries(3);
$this->dispatch(new RetryableMessage());
$this->assertMessages([new RetryableMessage()]);
}
}
Mock the Transport
$this->mockTransport();
Dispatch and Assert
$this->dispatch(new AsyncMessage());
$this->assertMessages([new AsyncMessage()]);
Service Provider
Extend Zenstruck\MessengerTest\MessengerTestServiceProvider if customizing behavior:
$this->app->register(MessengerTestServiceProvider::class);
Custom Assertions
Extend AssertsMessages for project-specific assertions:
class CustomAssertions extends AssertsMessages
{
public function assertMessageProcessed(MyMessage $message)
{
// Custom logic
}
}
Transport Mocking
$this->mockTransport() before dispatching messages will result in actual messages being sent to the queue.protected function setUp(): void
{
parent::setUp();
$this->mockTransport();
}
Message Matching
equals() in your message class:
public function equals($other): bool
{
return $this->id === $other->id;
}
Async Workers
$this->assertMessagesHandled() instead of $this->assertMessages():
$this->assertMessagesHandled([new AsyncMessage()]);
Retry Behavior (New)
$this->disableRetries();
$this->enableRetries() or $this->disableRetries() at the start of your test methods to control retry logic.Inspect Queued Messages
Use $this->getMessages() to debug:
$messages = $this->getMessages();
dd($messages);
Clear Queued Messages
Use $this->clearMessages() to reset state between tests:
$this->clearMessages();
Retry Debugging
Use $this->getRetryCount() to inspect how many times a message was retried:
$this->dispatch(new RetryableMessage());
$this->assertRetryCount(2); // Assert message was retried twice
Custom Message Bus If using a custom bus, bind it to the container:
$this->app->bind('messenger.bus', function () {
return new CustomBus([/* ... */]);
});
Transport Configuration
Ensure your config/messenger.php is properly set up for testing:
'transports' => [
'sync' => [
'dsn' => 'sync://',
],
],
Retry Configuration Retry behavior can now be controlled per test or globally via service provider:
// In a service provider
$this->app->make('events')->listen('messenger.test.start', function () {
$this->disableRetries(); // Disable retries for all tests
});
Custom Matchers
Extend Zenstruck\MessengerTest\Matcher\MessageMatcher for custom matching logic.
Event Listeners
Add listeners to messenger.test events for pre/post-test hooks:
$this->app->make('events')->listen('messenger.test.start', function () {
// Pre-test logic
});
Assertion Macros Add custom assertions via macros:
$this->assertMessages()->macro('assertProcessed', function (MyMessage $message) {
// Custom assertion logic
});
Retry Extensions (New) Extend retry behavior by implementing custom retry logic:
$this->app->bind('messenger.test.retry', function () {
return new CustomRetryHandler();
});
How can I help you explore Laravel packages today?