Skip to content

Integration MongoDB Extension

Aryeh Citron edited this page Apr 21, 2026 · 15 revisions

The TestTrackingDiagrams.Extensions.MongoDB package adds MongoDB operation tracking to your test diagrams using the driver's built-in command monitoring events. Instead of opaque internal database calls, your sequence diagrams show classified operations like Find → users with a clean mongodb:///mydb/users URI.


How It Works

The MongoDB .NET driver provides a first-class event subscription API via MongoClientSettings.ClusterConfigurator. MongoDbTrackingSubscriber subscribes to three events:

  • CommandStartedEvent — captures the command name, BsonDocument, and database namespace
  • CommandSucceededEvent — captures the reply and duration
  • CommandFailedEvent — captures the exception

The subscriber correlates start→success/failure pairs using RequestId via a ConcurrentDictionary, then logs both a request and response entry to RequestResponseLogger. Because it logs to the same logger as the standard TestTrackingMessageHandler, MongoDB operations appear alongside your HTTP API calls in the same sequence diagram.


Install

dotnet add package TestTrackingDiagrams.Extensions.MongoDB

Verbosity Levels

Level Label shown URI shown Request content Response content
Raw Find mydb.users filter={...} mongodb:///mydb/users Full BSON command Full BSON reply
Detailed Find → users mongodb:///mydb/users Filter text only None
Summarised Find mongodb:///mydb None None

The default is Detailed.


Classified Operations

Category Operations
CRUD Find, Insert, Update, Delete
Aggregation Aggregate, Count, Distinct
Atomic FindAndModify
Batch BulkWrite
DDL CreateIndex, DropIndex, CreateCollection, DropCollection
Metadata ListCollections, ListDatabases
Cursor GetMore (disabled by default)
Fallback Other (unrecognised commands)

Collection Name Extraction

The collection name is extracted from the first element of the BsonDocument command. For example:

  • { "find": "users", "filter": {...} } → collection = users
  • { "insert": "orders", "documents": [...] } → collection = orders
  • { "aggregate": 1, "pipeline": [...] } → database-level aggregate, collection = null

Setup

Option A: With MongoClientSettings Extension (Recommended)

var trackingOptions = new MongoDbTrackingOptions
{
    ServiceName = "MongoDB",
    CallingServiceName = "My API",
    Verbosity = MongoDbTrackingVerbosity.Detailed,
    CurrentTestInfoFetcher = () =>
    {
        var test = TestContext.Current.Test;
        return test is not null
            ? (test.TestDisplayName, test.UniqueID)
            : ("Unknown", "unknown");
    }
};

var settings = MongoClientSettings.FromConnectionString("mongodb://localhost:27017");
settings.WithTestTracking(trackingOptions);

var client = new MongoClient(settings);

WithTestTracking chains a tracking subscriber into ClusterConfigurator without replacing any existing configurator. This requires no production code changes.

Option B: Manual Subscriber Setup

If you need more control:

var trackingOptions = new MongoDbTrackingOptions
{
    ServiceName = "MongoDB",
    CallingServiceName = "My API",
    Verbosity = MongoDbTrackingVerbosity.Detailed,
    CurrentTestInfoFetcher = () =>
    {
        var test = TestContext.Current.Test;
        return test is not null
            ? (test.TestDisplayName, test.UniqueID)
            : ("Unknown", "unknown");
    }
};

var subscriber = new MongoDbTrackingSubscriber(trackingOptions);

var settings = MongoClientSettings.FromConnectionString("mongodb://localhost:27017");
settings.ClusterConfigurator = builder => subscriber.Subscribe(builder);

var client = new MongoClient(settings);

Option C: In DI-based Tests (WebApplicationFactory)

builder.ConfigureTestServices(services =>
{
    services.AddSingleton<IMongoClient>(sp =>
    {
        var trackingOptions = new MongoDbTrackingOptions
        {
            ServiceName = "MongoDB",
            CallingServiceName = "My API",
            Verbosity = MongoDbTrackingVerbosity.Detailed,
            CurrentTestInfoFetcher = () =>
            {
                var test = TestContext.Current.Test;
                return test is not null
                    ? (test.TestDisplayName, test.UniqueID)
                    : ("Unknown", "unknown");
            }
        };

        var settings = MongoClientSettings.FromConnectionString("mongodb://localhost:27017");
        settings.WithTestTracking(trackingOptions);

        return new MongoClient(settings);
    });
});

Configuration Reference

MongoDbTrackingOptions

Property Type Default Description
ServiceName string "MongoDB" The participant name shown in the diagram for the MongoDB service
CallingServiceName string "Caller" The participant name shown for the service making MongoDB calls
Verbosity MongoDbTrackingVerbosity Detailed Controls how much detail appears in the diagram (Raw, Detailed, Summarised)
CurrentTestInfoFetcher Func<(string Name, string Id)>? null Returns the current test's name and ID. Required — if null, commands are monitored but not logged
CurrentStepTypeFetcher Func<string?>? null Optional — returns the current BDD step type (Given/When/Then)
IgnoredCommands HashSet<string> See below Commands to ignore entirely (not logged even when test info is available)
TrackGetMore bool false Whether to track getMore cursor continuation commands

Default Ignored Commands

These MongoDB internal/handshake commands are ignored by default:

  • isMaster, hello — server handshake
  • saslStart, saslContinue — authentication
  • ping — health check
  • buildInfo — server metadata
  • getLastError — legacy error check
  • killCursors — cursor cleanup

Override IgnoredCommands to customise:

new MongoDbTrackingOptions
{
    IgnoredCommands = ["isMaster", "hello"] // Only ignore these two
}

ITrackingComponent

MongoDbTrackingSubscriber implements ITrackingComponent and auto-registers with TrackingComponentRegistry. The invocation count increments for every command (including ignored ones), so you can verify MongoDB was actually contacted:

var subscriber = new MongoDbTrackingSubscriber(options);

// ... run test ...

Assert.True(subscriber.WasInvoked);
Assert.Equal(3, subscriber.InvocationCount);

Or use TrackingComponentRegistry.GetUnusedComponents() to find services that were wired up but never called.


Event Correlation

The subscriber uses ConcurrentDictionary<int, PendingOperation> keyed by RequestId to correlate CommandStartedEventCommandSucceededEvent/CommandFailedEvent. This handles concurrent operations correctly — multiple in-flight commands on different connections don't interfere with each other.

If a CommandSucceededEvent or CommandFailedEvent arrives without a matching CommandStartedEvent (e.g., due to race conditions or late subscription), it is silently ignored.

Home


Demo


Getting Started

Common Tasks

Integration Guides

Extensions

Configuration

Features

Reference

Clone this wiki locally