Rig.TUnit.Messaging.RabbitMq
0.1.0-beta.2
dotnet add package Rig.TUnit.Messaging.RabbitMq --version 0.1.0-beta.2
NuGet\Install-Package Rig.TUnit.Messaging.RabbitMq -Version 0.1.0-beta.2
<PackageReference Include="Rig.TUnit.Messaging.RabbitMq" Version="0.1.0-beta.2" />
<PackageVersion Include="Rig.TUnit.Messaging.RabbitMq" Version="0.1.0-beta.2" />
<PackageReference Include="Rig.TUnit.Messaging.RabbitMq" />
paket add Rig.TUnit.Messaging.RabbitMq --version 0.1.0-beta.2
#r "nuget: Rig.TUnit.Messaging.RabbitMq, 0.1.0-beta.2"
#:package Rig.TUnit.Messaging.RabbitMq@0.1.0-beta.2
#addin nuget:?package=Rig.TUnit.Messaging.RabbitMq&version=0.1.0-beta.2&prerelease
#tool nuget:?package=Rig.TUnit.Messaging.RabbitMq&version=0.1.0-beta.2&prerelease
Rig.TUnit.Messaging.RabbitMq
Testcontainers-backed RabbitMQ fixture (
rabbitmq:3-management) with async listener/sender onRabbitMQ.Client7.x and a fluent topology builder for exchanges, bindings, queue arguments, and DLX.
What this package is
The Rig.TUnit RabbitMQ provider. RabbitMqFixture spins the management-
plugin-enabled image (HTTP admin UI on :15672 for debugging), exposes
the AMQP connection string, and ships async listener / sender helpers
on the new RabbitMQ.Client 7.x async-only API. Ships:
RabbitMqEventSender— async sender with aSendContextoverload mappingPartitionKey→ routing key and writing thex-partition-keyAMQP header. Explicitexchange+routingKeyparameters; legacy default-exchange behaviour preserved when omitted.RabbitMqListener— declares its queue + (optional) exchange + binding beforeBasicConsumeAsync; readsx-partition-keyintoCapturedMessage.SessionKey. Decode failures are returned as a typed error via theErrorscollection (the consumer runsautoAck:trueso a throw would silently drop the payload).RabbitMqTopologyBuilder+ provider-scoped interfaces (IRabbitMqTopologyBuilder,IRabbitMqExchangeConfig,IRabbitMqQueueConfig,ExchangeTypeenum) wired viaRabbitMqRigBuilder.WithTopology(…).- Queue-argument plumbing —
IRabbitMqQueueConfig.WithMessageTtl,WithMaxLength,WithMaxPriority,WithDeadLetterExchange,WithQuorum. Each maps to the corresponding AMQPx-…header. DeadLetterAssert— DLX/DLQ inspection that knows the convention the topology builder wires up.
When to use it
- Integration tests for RabbitMQ queues, exchanges, bindings.
- Asserting topic-exchange fan-out across multiple bound queues.
- Asserting dead-letter behaviour under retry policies (DLX on nack).
- Verifying routing-key patterns (direct / topic / fanout / headers).
- Priority-queue ordering and quorum-queue durability.
- Not for: pure unit tests of message-handler logic.
Prerequisites
- .NET 10 SDK
- Docker Desktop / Colima (RabbitMQ image ~220 MB)
RabbitMQ.Client7.x (transitive — async-only API)
Quick start
using Rig.TUnit.Messaging.Helpers;
using Rig.TUnit.Messaging.RabbitMq.Fixtures;
using Rig.TUnit.Messaging.RabbitMq.Helpers;
await using var fx = new RabbitMqFixture();
await fx.InitializeAsync();
// Default-exchange path (legacy — unchanged).
await using var sender = new RabbitMqEventSender(fx.ConnectionString, queue: "orders");
await sender.SendAsync("{\"orderId\":1}", correlationId: "abc");
// Topic-exchange + routing-key path with SendContext.PartitionKey on the new overload.
await using var topicSender = new RabbitMqEventSender(
fx.ConnectionString, exchange: "events", routingKey: "order.created");
await topicSender.SendAsync(
"{\"orderId\":1}",
context: new SendContext(PartitionKey: "order.created"),
ct: ct);
Topic-exchange + DLX topology via the WithTopology rig hook:
services.AddRigTUnit(rig =>
rig.UseRabbitMq(RigConnect.FromValue(fx.ConnectionString), r =>
r.WithTopology(t =>
t.Exchange("events", ExchangeType.Topic)
.Exchange("events-dlx", ExchangeType.Fanout)
.Queue("eu-orders", c => c
.WithMessageTtl(TimeSpan.FromMinutes(5))
.WithDeadLetterExchange("events-dlx"))
.Queue("dlq-store")
.Binding("events", "eu-orders", "order.eu.*")
.Binding("events-dlx", "dlq-store", ""))));
Options
| Property | Type | Default | Description |
|---|---|---|---|
Image |
string |
"rabbitmq:3-management" |
Image with admin UI |
StartupTimeoutSeconds |
int |
60 |
RabbitMQ boot |
VHost |
string |
"/" |
Virtual host |
Username |
string |
"rigtunit" |
Default user |
Password |
string |
"rigtunit" |
Default password |
Fixture + helper APIs
Rig.TUnit.Messaging.RabbitMq.Fixtures.RabbitMqFixtureRig.TUnit.Messaging.RabbitMq.Options.RabbitMqFixtureOptionsRig.TUnit.Messaging.RabbitMq.Builder.RabbitMqRigBuilder— shipsWithTopology(Action<IRabbitMqTopologyBuilder>).Rig.TUnit.Messaging.RabbitMq.Helpers.RabbitMqListener— exposes the typedErrorscollection for decode-failure assertion.Rig.TUnit.Messaging.RabbitMq.Helpers.RabbitMqEventSender— shipsSendAsync(string, SendContext, …)overload + explicitexchange/routingKeyparameters.Rig.TUnit.Messaging.RabbitMq.Topology.IRabbitMqTopologyBuilderRig.TUnit.Messaging.RabbitMq.Topology.IRabbitMqExchangeConfigRig.TUnit.Messaging.RabbitMq.Topology.IRabbitMqQueueConfig—WithMessageTtl,WithMaxLength,WithMaxPriority,WithDeadLetterExchange,WithQuorum.Rig.TUnit.Messaging.RabbitMq.Topology.ExchangeType— enum.Rig.TUnit.Messaging.RabbitMq.Topology.RabbitMqTopologyBuilder
Per-test isolation
Per-test queue and DLQ: orders_{IsolationKey:short} +
orders_{IsolationKey:short}.dlq. Teardown deletes both queues.
Parallelism + performance
- First-run pull: ~20 s.
- Warm startup: ~8 s (plugins take time).
- Per-op publish: ~2 ms.
- Parallelism: 8+ concurrent tests; queue-level isolation is trivial.
Troubleshooting
PRECONDITION_FAILED - inequivalent arg— queue redeclared with different args between runs; teardown must delete, or declare with identical args each time.- Consumer hangs on
Received— the listener's ack-policy is manual by default; calllistener.AckAsync(deliveryTag)after each message, or use the auto-ack option.
See docs/troubleshooting.md#rabbitmq.
Provider quirks + edge cases
- RabbitMQ 7.x async-only
RabbitMQ.Clientbroke the syncIModelcontract — all listener/sender code must beasync. - Durable queues survive broker restart; ephemeral queues do not. Test assertion style must match.
- DLX routing requires
x-dead-letter-exchangeon queue declaration — declare viaIRabbitMqQueueConfig.WithDeadLetterExchange(name)so the topology builder writes the argument. - Idempotent topology re-apply only succeeds when the second declaration
uses identical arguments. Re-declaring with conflicting args
throws
OperationInterruptedException(PRECONDITION_FAILED); seeWithTopology_CalledTwice_IsIdempotenttest for the contract. - Quorum queues (
IRabbitMqQueueConfig.WithQuorum()) survive broker restart and require RabbitMQ ≥ 3.8; the management image bundled ships with 3.x. - Listener runs
autoAck:true, so decode failures are returned viaRabbitMqListener.Errorsrather than re-thrown — the message has already been removed from the queue by the time the callback runs.
Benchmarks
See RabbitMqMessagingBenchmarks.cs;
baseline in benchmarks/baseline-005.json.
Related docs
- Architecture diagram
- Glossary
- Provider deep-dive:
docs/providers/rabbitmq.md(exchange + binding + DLX example, queue-args reference table). - Family base:
Rig.TUnit.Messaging - Feature design: Sessions & Partitions · Topology Builder
License
MIT. See LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Bogus (>= 35.6.1)
- Microsoft.Extensions.Configuration (>= 10.0.0)
- Microsoft.Extensions.Configuration.Binder (>= 10.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Options (>= 10.0.0)
- Microsoft.Extensions.Options.DataAnnotations (>= 10.0.0)
- RabbitMQ.Client (>= 7.0.0)
- Rig.TUnit.Messaging (>= 0.1.0-beta.2)
- Testcontainers (>= 4.11.0)
- Testcontainers.RabbitMq (>= 4.11.0)
- TUnit.Core (>= 1.34.5)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Rig.TUnit.Messaging.RabbitMq:
| Package | Downloads |
|---|---|
|
Rig.TUnit.All
Meta-package containing every Rig.TUnit.* package. DISCOURAGED — prefer per-feature or per-stack meta-packages (Rig.TUnit, Rig.TUnit.Microservices). |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-beta.2 | 48 | 4/27/2026 |
| 0.0.0-alpha.0.14 | 59 | 4/26/2026 |