How to Mock RabbitMQ Ack Nack Requeue in Python

A mock RabbitMQ channel and consumer that simulates ack, nack, and requeue handling for testing message processing logic without a broker.

Easy Python 3.9+ Aug 9, 2026 Streaming & messaging 14 views 0 copies

Python code

52 lines
Python 3.9+
import json
from collections import deque


class MockChannel:
    def __init__(self):
        self.acked = []
        self.nacked = []
        self.requeued = []

    def basic_ack(self, delivery_tag):
        self.acked.append(delivery_tag)

    def basic_nack(self, delivery_tag, requeue=False):
        self.nacked.append({"tag": delivery_tag, "requeue": requeue})
        if requeue:
            self.requeued.append(delivery_tag)


class MockConsumer:
    def __init__(self, messages):
        self.channel = MockChannel()
        self.message_queue = deque(messages)
        self.delivery_tag_counter = 0

    def process_next(self):
        if not self.message_queue:
            return None
        message = self.message_queue.popleft()
        self.delivery_tag_counter += 1
        tag = self.delivery_tag_counter
        payload = json.loads(message)
        if payload.get("valid"):
            self.channel.basic_ack(tag)
        else:
            self.channel.basic_nack(tag, requeue=True)
        return payload


if __name__ == "__main__":
    messages = [
        '{"id": 1, "valid": true}',
        '{"id": 2, "valid": false}',
        '{"id": 3, "valid": true}',
    ]
    consumer = MockConsumer(messages)
    while consumer.process_next() is not None:
        pass

    print("Acked:", consumer.channel.acked)
    print("Nacked:", consumer.channel.nacked)
    print("Requeued:", consumer.channel.requeued)

Output

stdout
Acked: [1, 3]
Nacked: [{'tag': 2, 'requeue': True}]
Requeued: [2]

How it works

The MockChannel captures ack and nack calls with delivery tags, recording requeued tags separately. Each message gets a sequential tag as it's pulled from a deque. The consumer parses JSON and checks the valid field: true messages are acked, false messages are nacked with requeue=True. The main loop drains all messages, and the channel's history is printed to verify behavior.

Common mistakes

  • Forgetting to simulate delivery tag increments per message
  • Not distinguishing between nack with and without requeue when recording state
  • Overlooking that deque.popleft is O(1) but list.pop(0) is O(n)

Variations

  1. Use unittest.mock.MagicMock for a lighter, less structured mock
  2. Add an explicit sleep or callback to simulate async processing

Real-world use cases

  • Unit-testing consumer logic that must ack successful messages and requeue dead-letter candidates.
  • Simulating broker behavior for integration tests of a queue-processing service without Docker.
  • Validating retry policies and poison-message handling in a background job runner.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Streaming & messaging

Related tutorials and quizzes for this topic.