Messaggero.Testing
0.0.1
dotnet add package Messaggero.Testing --version 0.0.1
NuGet\Install-Package Messaggero.Testing -Version 0.0.1
<PackageReference Include="Messaggero.Testing" Version="0.0.1" />
<PackageVersion Include="Messaggero.Testing" Version="0.0.1" />
<PackageReference Include="Messaggero.Testing" />
paket add Messaggero.Testing --version 0.0.1
#r "nuget: Messaggero.Testing, 0.0.1"
#:package Messaggero.Testing@0.0.1
#addin nuget:?package=Messaggero.Testing&version=0.0.1
#tool nuget:?package=Messaggero.Testing&version=0.0.1
Messaggero.Testing
In-memory transport adapter and test utilities for Messaggero. Provides two complementary testing approaches:
TestMessageBus— lightweightIMessageBusstub for unit-testing publish behaviour without standing up the full pipeline.InMemoryTransportAdapter/AddInMemory— full Messaggero pipeline running in-process, no broker required.
Add it only to test projects — it has no place in production assemblies.
TestMessageBus — unit tests
TestMessageBus is a thread-safe IMessageBus implementation that records every PublishAsync call. Use it when the unit under test publishes messages and you want to assert on what was published, without running handlers or any routing logic.
Basic usage
[Fact]
public async Task PlaceOrder_PublishesOrderPlacedEvent()
{
var bus = new TestMessageBus();
var svc = new OrderService(bus);
await svc.PlaceOrderAsync("ORD-1", 99.99m);
bus.AssertPublished<OrderPlaced>();
var events = bus.GetPublishedMessages<OrderPlaced>();
Assert.Single(events, e => e.OrderId == "ORD-1");
}
API reference
| Method | Description |
|---|---|
AssertPublished<T>() |
Throws InvalidOperationException if no message of type T was published |
GetPublishedMessages<T>() |
Returns all published messages of type T as IReadOnlyList<T> |
GetAllPublished() |
Returns all captured entries as (string Type, object Message, MessageHeaders Headers) |
Reset() |
Clears all captured messages |
Asserting headers
var bus = new TestMessageBus();
var svc = new OrderService(bus);
await svc.PlaceOrderAsync("ORD-1", 99.99m);
var all = bus.GetAllPublished();
var (type, message, headers) = all.Single();
Assert.Equal(nameof(OrderPlaced), type);
Assert.Equal("ORD-1", ((OrderPlaced)message).OrderId);
Assert.Equal("tenant-42", headers["tenant-id"]);
DI registration
Swap the real IMessageBus for TestMessageBus in your test's DI setup:
var services = new ServiceCollection();
services.AddSingleton<IMessageBus, TestMessageBus>();
services.AddTransient<OrderService>();
var provider = services.BuildServiceProvider();
var svc = provider.GetRequiredService<OrderService>();
var bus = (TestMessageBus)provider.GetRequiredService<IMessageBus>();
await svc.PlaceOrderAsync("ORD-1", 99.99m);
bus.AssertPublished<OrderPlaced>();
AddInMemory — integration / pipeline tests
AddInMemory registers an InMemoryTransportAdapter with the full Messaggero pipeline. Messages flow through routing, serialization, the dispatch loop, and your handlers — exactly as in production, but without a broker.
Basic usage
[Fact]
public async Task Handler_IsInvokedWhenMessagePublished()
{
var services = new ServiceCollection();
services.AddLogging();
services.AddMessaggero(messaging =>
{
messaging
.AddInMemory("mem")
.Route<OrderPlaced>(r => r.ToTransport("mem"))
.RegisterHandler<OrderPlacedHandler, OrderPlaced>();
});
await using var provider = services.BuildServiceProvider();
var host = provider.GetRequiredService<MessagingHost>();
await host.StartAsync(CancellationToken.None);
var bus = provider.GetRequiredService<IMessageBus>();
await bus.PublishAsync(new OrderPlaced("ORD-42", 50m));
// assert via handler side-effects or inspect the adapter directly
}
Inspecting the adapter
Resolve InMemoryTransportAdapter directly from the host to assert on published, pending, and dead-lettered messages:
var adapter = host.Adapters["mem"] as InMemoryTransportAdapter;
// All messages that passed through PublishAsync
Assert.Single(adapter.PublishedMessages, m => m.Type == nameof(OrderPlaced));
// Messages that were nack'd / handler threw after all retries
Assert.Empty(adapter.DeadLetterMessages);
// Messages delivered to handlers but not yet ack'd
Assert.Empty(adapter.PendingMessages);
InMemoryTransportAdapter properties
| Property | Type | Description |
|---|---|---|
PublishedMessages |
IReadOnlyCollection<Message> |
Every message passed to PublishAsync |
DeadLetterMessages |
IReadOnlyCollection<Message> |
Messages moved here on RejectAsync (handler threw, retries exhausted) |
PendingMessages |
IReadOnlyCollection<Message> |
Delivered to handlers but not yet ack'd or nack'd |
Testing retry behaviour
Configure a retry policy on the in-memory adapter just as you would on a real broker adapter:
services.AddMessaggero(messaging =>
{
messaging
.AddInMemory("mem")
.Route<OrderPlaced>(r => r.ToTransport("mem"))
.RegisterHandler<FlakyOrderHandler, OrderPlaced>();
});
// FlakyOrderHandler throws on first two attempts, succeeds on third
// After all MaxAttempts exhausted, the message lands in DeadLetterMessages
The in-memory adapter calls
RejectAsyncon nack, which moves the message toDeadLetterMessages. There is no requeue — use this to verify dead-letter routing logic.
Handler isolation — no host needed
For the simplest case, test handler logic directly without any Messaggero infrastructure:
[Fact]
public async Task Handler_ProcessesOrderCorrectly()
{
var handler = new OrderPlacedHandler();
var context = new MessageContext
{
MessageId = "test-1",
MessageType = nameof(OrderPlaced),
SourceTransport = "test",
Headers = new MessageHeaders(),
Timestamp = DateTimeOffset.UtcNow,
DeliveryAttempt = 1,
};
await handler.HandleAsync(
new OrderPlaced("ORD-42", 99.99m),
context,
CancellationToken.None);
// assert handler side-effects directly
}
Delivery Semantics
| Guarantee | At-most-once (default) |
|---|---|
| Ordering | FIFO per destination |
| Ack model | Removes message from PendingMessages |
| Nack behaviour | Moves message to DeadLetterMessages — no requeue |
The in-memory adapter is not durable. All state is held in memory and lost when the adapter is disposed. It is intended for tests only.
Requirements
- .NET 10.0+
- Messaggero (core)
| 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
- Messaggero (>= 0.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.1 | 102 | 4/19/2026 |