Testing

There is an in-memory transport. It needs no Docker, starts instantly, and implements routing, prefetch and settlement — which is what most tests actually exercise.

try (AceMq mq = AceMq.connect("memory://orders")) {
    mq.declareExchange("orders", "topic");
    mq.declareQueue("orders.new", QueueType.CLASSIC, Map.of());
    mq.bind("orders.new", "orders", "order.*");

    mq.publisher("orders", "order.placed", Order.class).send(order);
}

Add it as a test dependency:

<dependency>
  <groupId>org.acemq</groupId>
  <artifactId>acemq-amqp-test</artifactId>
  <version>0.7.15</version>
  <scope>test</scope>
</dependency>

Two connections to the same name share a broker; a different name is a different broker. Prefer a unique name per test over resetting shared state:

AceMq.connect("memory://orders-" + UUID.randomUUID());

It is a fake, not a simulator

This matters, and the library is deliberate about it. The in-memory broker implements routing, prefetch, settlement, per-queue and per-message expiry, and dead-lettering. It does not implement replication, persistence, delayed delivery, or streams — and it does not claim those capabilities, so code depending on them fails here for the same reason it would fail against a broker that lacks them.

Concretely: streams need a real broker. mq.declareStream(...) on memory:// refuses rather than quietly creating a classic queue.

Where the fake and RabbitMQ genuinely differ, the difference is documented rather than hidden. Blocked connections are the clearest example — see below.

Testing failure

Simulating a broker under a memory alarm, which is otherwise nearly impossible to reproduce:

InMemoryTransport.block("orders", "low on memory");

assertThatThrownBy(() -> publisher.send(order))
        .isInstanceOf(ConnectionBlockedException.class);

InMemoryTransport.unblock("orders");

One deliberate difference: here isBlocked() becomes true immediately, whereas RabbitMQ only tells a connection it is blocked when that connection next publishes. Against a real broker the first message into an alarm is already on the wire, so it may have arrived; here nothing is ever written, and mayHaveBeenPublished() is always false. A test that needs the uncertain case needs a real broker.

Testing against a real broker

Use Testcontainers for the cases the fake cannot cover — streams, replication, persistence, and anything where you want to be sure:

@Container
static final RabbitMQContainer BROKER =
        new RabbitMQContainer(DockerImageName.parse("rabbitmq:4-management"));

AceMq mq = AceMq.connect(BROKER.getAmqpUrl());

The library's own suite does exactly this, and runs both: the fake for speed, real RabbitMQ for truth. When the two disagree, the fake is wrong.