Lepus ships a test-mode module that captures publishes and runs consumer perform methods synchronously — no RabbitMQ connection required.
Enabling
# spec/spec_helper.rb (RSpec)require 'lepus/testing'
RSpec.configure do |config| config.before(:each) { Lepus::Testing.enable! } config.after(:each) { Lepus::Testing.reset! }endOnce enabled:
- Publishes don’t hit RabbitMQ. They’re captured in an in-memory buffer keyed by producer class.
- Consumer handling is synchronous when invoked through
Lepus::Testing.consumer_perform.
Testing a consumer
describe OrdersConsumer do it 'creates an order' do result = Lepus::Testing.consumer_perform( OrdersConsumer, { order_id: 42, total: 99.99 } )
expect(result).to eq(:ack) expect(Order.find(42).total).to eq(99.99) end
it 'rejects invalid payloads' do result = Lepus::Testing.consumer_perform(OrdersConsumer, { bad: 'data' }) expect(result).to eq(:reject) end
it 'sets delivery info and metadata' do result = Lepus::Testing.consumer_perform( OrdersConsumer, { order_id: 7 }, delivery_info: { routing_key: 'order.created' }, metadata: { correlation_id: 'abc-123' } ) expect(result).to eq(:ack) endendconsumer_perform signature:
Lepus::Testing.consumer_perform( ConsumerClass, payload, delivery_info: {}, metadata: {})It builds a Lepus::Message, runs the full middleware chain (including global middlewares), and returns the disposition symbol.
Testing a producer
describe OrdersProducer do it 'publishes the order' do order = Order.create!(id: 42, total: 99.99) OrdersProducer.order_created(order)
messages = Lepus::Testing.producer_messages(OrdersProducer) expect(messages.size).to eq(1) expect(messages[0][:payload]).to include(order_id: 42) expect(messages[0][:routing_key]).to eq('order.created') end
it 'runs through middleware' do OrdersProducer.publish({ foo: 'bar' }, routing_key: 'x')
msg = Lepus::Testing.producer_messages(OrdersProducer).last expect(msg[:metadata][:correlation_id]).to be_present # set by :correlation_id middleware expect(msg[:metadata][:content_type]).to eq('application/json') endendproducer_messages(ProducerClass) returns an array of hashes with :payload, :routing_key, :delivery_info, :metadata.
RSpec matchers
require 'lepus/testing/rspec_matchers'Then:
expect { OrdersProducer.order_created(order) } .to have_published_message(OrdersProducer) .with_payload(include(order_id: order.id)) .to_routing_key('order.created')Testing middleware in isolation
Middlewares are plain Ruby objects with a call(message, app) method. Unit-test them directly:
describe LogLevelMiddleware do it 'logs before calling down the chain' do middleware = LogLevelMiddleware.new(level: :debug) message = Lepus::Testing::MessageBuilder.build(payload: { x: 1 }) captured = nil
allow(Lepus.logger).to receive(:debug) { |msg| captured = msg } middleware.call(message, ->(m) { :ack })
expect(captured).to include('Processing:') endendLepus::Testing::MessageBuilder.build(**kwargs) builds a realistic Lepus::Message for unit tests.
Resetting between tests
Lepus::Testing.reset! clears captured publishes. In shared setup:
RSpec.configure do |config| config.before(:each) { Lepus::Testing.enable!; Lepus::Testing.reset! }endWhen you do need a real RabbitMQ
Integration tests that exercise the full round-trip (publish → RabbitMQ → consume) benefit from a real broker. Use docker run rabbitmq:3-management or your test infra’s existing one, and skip Lepus::Testing.enable! for those specs.