Messaggero.Testing 0.0.1

dotnet add package Messaggero.Testing --version 0.0.1
                    
NuGet\Install-Package Messaggero.Testing -Version 0.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Messaggero.Testing" Version="0.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Messaggero.Testing" Version="0.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Messaggero.Testing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Messaggero.Testing --version 0.0.1
                    
#r "nuget: Messaggero.Testing, 0.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Messaggero.Testing@0.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Messaggero.Testing&version=0.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Messaggero.Testing&version=0.0.1
                    
Install as a Cake Tool

Messaggero.Testing

In-memory transport adapter and test utilities for Messaggero. Provides two complementary testing approaches:

  • TestMessageBus — lightweight IMessageBus stub 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 RejectAsync on nack, which moves the message to DeadLetterMessages. 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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