Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Null Laravel Package

enqueue/null

Null transport implementation for Queue Interop that discards messages instead of sending them anywhere. Use it as a mock or no-op queue in tests and development to verify message flow without a real broker.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the transport alongside the Enqueue context you'll be using in Laravel:

composer require enqueue/null

The package is tiny — it ships a NullTransportFactory, NullTransport, NullTopic, and a NullConsumer that all live in Enqueue\Null. There is no service provider; it plugs into the php-enqueue/enqueue abstraction, not Laravel's own QUEUE_CONNECTION config. Two things to internalize before writing a line of code:

  1. This is not QUEUE_CONNECTION=null. Laravel ships its own null driver (which literally does nothing) and a sync driver (which runs jobs inline). enqueue/null is the null transport for the Enqueue ecosystem. It only matters if you're already using enqueue/*, enqueue/laravel, or enqueue/simple-client for messaging. If you're on Laravel's default queue, this package adds nothing — use sync or null instead.

  2. It is a contract-preserving stub. Every call returns the transport's own dummy Message/Context objects so your producer, consumer, and extension code can run end-to-end without a broker.

The first use case: swap your Redis/RabbitMQ transport for the null transport in tests so producer code can be executed without a live broker.

use Enqueue\Null\NullConnectionFactory;
use Enqueue\Null\NullTransportFactory;
use Interop\Queue\Context;

// Typically in a test bootstrap or a test service provider
$factory = new NullTransportFactory();
$context = $factory->createContext();

$this->app->instance(Context::class, $context);

Look first at NullContext, NullProducer, NullConsumer in src/. The whole surface is a few hundred lines — read it in one sitting and you'll know exactly what it does (and doesn't) do.

Implementation Patterns

Pattern 1: Transport swap in tests. Bind the Context interface in a test service provider and let the rest of your app resolve it normally. This keeps production code free of if (app()->environment()) branching.

// app/Providers/EnqueueServiceProvider.php
public function register(): void
{
    $this->app->singleton(Context::class, function () {
        $factory = app()->environment('testing')
            ? new NullTransportFactory()
            : new AmqpConnectionFactory(config('enqueue.dsn'));

        return $factory->createContext();
    });
}

Pattern 2: Asserting producer behavior without a broker. Because NullProducer::send() returns a NullMessage, you can assert on the message your code produced before it hits the void. Use a spy decorator rather than asserting on the null transport itself — the null transport will never tell you what was sent.

final class SpyProducer implements Producer
{
    public array $sent = [];

    public function __construct(private Producer $inner) {}

    public function send(Message $message, array $extensions = []): void
    {
        $this->sent[] = $message;
        $this->inner->send($message, $extensions);
    }
    // ...
}

Pattern 3: Local dev with enqueue/simple-client. If you're using the Simple Client abstraction for dispatching jobs, point the client at a null transport locally so devs don't need Docker, and let CI run against a real broker. This is the sweet spot for this package — you keep the exact same client API, just no wire traffic.

Pattern 4: CI fan-out. In a matrix build, run most jobs against NullTransportFactory and reserve one "integration" job for a service container (RabbitMQ, Redis, SQS). The null runs finish in milliseconds and validate your application wiring; the real run validates broker interaction.

Pattern 5: Consumer contract tests. NullConsumer::receive() returns null immediately (non-blocking). That's actually useful — you can write a test that drives a consumer loop to termination in one iteration and verifies it exits cleanly.

Integration tip: If you want real Laravel queue integration (Horizon, dispatch(), ShouldQueue), don't reach for this package. Use Laravel's Queue::fake() for assertions and the sync driver for behaviour. Reserve enqueue/null for Enqueue-based code paths.

Gotchas and Tips

  • It silently discards everything. No exception, no log, no dead-letter. NullProducer::send() succeeds unconditionally. If your code assumes a downstream ack, it will look fine in tests and fail in production when the real broker refuses the message.
  • Don't use it to assert delivery. There is no "was this sent?" API. The transport is a stub, not a mock framework. Inject a spy (Pattern 2) or use Queue::fake()/Queue::assertPushed() if you're on Laravel's queue.
  • receive() returns null, not a message. Consumer loops written with $context->createConsumer($queue)->receive(1000) will see an immediate null. Any while (true) { $msg = receive(); ... } loop will spin hot if you forget to break on null. Add a bounded iteration or timeout in tests.
  • No extensions are exercised. NullProducer::send() accepts the $extensions array but ignores each one. If you rely on DelayExtension, PriorityExtension, or MessageIdExtension semantics, those are no-ops here. Test them against a real transport.
  • createQueue/createTopic are inert. Queues and topics returned by NullContext have no lifecycle — no declare, no purge, no broker-side existence check. Code that calls $context->createQueue('foo')->setArgument(...) will not throw, but nothing happens.
  • Config quirk: no DSN scheme works. Unlike other Enqueue factories, there is no null:// registration in enqueue/simple-client's factory resolver by default in older versions. If you get Could not find factory for scheme "null", register new NullConnectionFactory() explicitly in your connection factory collection.
  • Version pinning matters. Enqueue split enqueue/null out of the monorepo around v0.9/0.10. composer show enqueue/null should match the rest of your enqueue/* versions; mismatches cause interface-not-found errors at runtime that are painful to diagnose because they surface from a container binding, not the class you thought you were touching.
  • Extension point is the transport, not the message. If you need richer test behaviour (recording, replay, assertion), write a decorator implementing Interop\Queue\Producer/Consumer and wrap either the null transport or the real one. Don't fork the package — it's deliberately tiny and any behaviour you add belongs in your own test scaffolding.
  • Debugging hint: because messages vanish, the fastest way to see what was produced is to temporarily swap the inner transport for enqueue/fs (filesystem transport). Same API, messages land in a directory, delete afterwards. This is a much better debugging story than logging inside NullProducer.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
henzeb/housepedia-intelligence-laravel
aliqsm/laravel-authkit
itsjustvita/laravel-wp-migrator
uslanozan/laravel-cache-contract
adilazhari/laravel-trace
ulsyairil/ai-local-guardrails
dzwallet/laravel-sdk
glc36/maxloop-kernel
ikhbarnuridev/filament-mega-menu
mydnic/volet-chatbot
enadstack/laravel-localization
mydnic/volet-feature-board-filament-plugin
wmde/email-address
refinery29/test-util
dees040/laravel-api-responses
teamzac/geocoder
ideatica/config-writer
keaton-php/pipe-dream
jacksonwebservices/laravel-user-suite
maksimru/conditional-laravel-debugbar