Skip to content

Migration Guide

Aryeh Citron edited this page May 12, 2026 · 3 revisions

Migration Guide

Migrating from Mongo2Go

Before (Mongo2Go)

public class OrderTests : IDisposable
{
    private readonly MongoDbRunner _runner;
    private readonly IMongoCollection<Order> _collection;

    public OrderTests()
    {
        _runner = MongoDbRunner.Start();
        var client = new MongoClient(_runner.ConnectionString);
        var database = client.GetDatabase("testdb");
        _collection = database.GetCollection<Order>("orders");
    }

    public void Dispose() => _runner.Dispose();

    [Fact]
    public async Task Can_insert_and_find()
    {
        await _collection.InsertOneAsync(new Order { Total = 100 });
        var found = await _collection.Find(o => o.Total == 100).FirstOrDefaultAsync();
        Assert.NotNull(found);
    }
}

After (InMemoryEmulator)

public class OrderTests
{
    private readonly IMongoCollection<Order> _collection;

    public OrderTests()
    {
        var result = InMemoryMongo.Create<Order>("orders");
        _collection = result.Collection;
        // No runner to start, no connection string
        // IMongoClient.Dispose() is a no-op — no cleanup needed
    }

    [Fact]
    public async Task Can_insert_and_find()
    {
        await _collection.InsertOneAsync(new Order { Total = 100 });
        var found = await _collection.Find(o => o.Total == 100).FirstOrDefaultAsync();
        Assert.NotNull(found);
    }
}

Step-by-step

  1. Remove the Mongo2Go NuGet package
  2. Add InMemoryEmulator.MongoDB
  3. Replace MongoDbRunner.Start() + MongoClient(connectionString) with InMemoryMongo.Create<T>()
  4. Remove IDisposable / Dispose() for the runner
  5. Remove any timeout/retry logic for mongod startup
  6. Tests should pass without further changes

Migrating from Testcontainers.MongoDB

Before (Testcontainers)

public class OrderTests : IAsyncLifetime
{
    private readonly MongoDbContainer _container;
    private IMongoCollection<Order> _collection = null!;

    public OrderTests()
    {
        _container = new MongoDbBuilder()
            .WithImage("mongo:7.0")
            .Build();
    }

    public async Task InitializeAsync()
    {
        await _container.StartAsync();
        var client = new MongoClient(_container.GetConnectionString());
        _collection = client.GetDatabase("testdb").GetCollection<Order>("orders");
    }

    public async Task DisposeAsync() => await _container.DisposeAsync();

    [Fact]
    public async Task Can_insert_and_find()
    {
        await _collection.InsertOneAsync(new Order { Total = 100 });
        var found = await _collection.Find(o => o.Total == 100).FirstOrDefaultAsync();
        Assert.NotNull(found);
    }
}

After (InMemoryEmulator)

public class OrderTests
{
    private readonly IMongoCollection<Order> _collection;

    public OrderTests()
    {
        _collection = InMemoryMongo.Create<Order>("orders").Collection;
    }

    [Fact]
    public async Task Can_insert_and_find()
    {
        await _collection.InsertOneAsync(new Order { Total = 100 });
        var found = await _collection.Find(o => o.Total == 100).FirstOrDefaultAsync();
        Assert.NotNull(found);
    }
}

Step-by-step

  1. Remove Testcontainers.MongoDB NuGet package
  2. Add InMemoryEmulator.MongoDB
  3. Remove the IAsyncLifetime implementation and container setup
  4. Replace container + client creation with InMemoryMongo.Create<T>()
  5. Remove Docker dependency from CI configuration
  6. Tests should pass without further changes

Migrating from Manual Mocking

If you're using Moq or NSubstitute to mock IMongoCollection<T>:

Before (Moq)

var mockCollection = new Mock<IMongoCollection<Order>>();
mockCollection.Setup(c => c.FindAsync(It.IsAny<FilterDefinition<Order>>(), ...))
    .ReturnsAsync(mockCursor.Object);
// 50+ lines of setup per test...

After (InMemoryEmulator)

var collection = InMemoryMongo.Create<Order>("orders").Collection;
// Real query semantics, zero mock setup

Benefits

  • Real filter evaluation — your filters are actually tested
  • Real update application$set, $inc, $push actually work
  • No mock maintenance — refactoring doesn't break test setup
  • Integration-level confidence — tests verify actual MongoDB behavior

DI Migration

If your production code uses DI:

// In your test project's WebApplicationFactory or test setup:
services.UseInMemoryMongoDB(options =>
{
    options.DatabaseName = "testdb";
    options.AddCollection<Order>("orders");
});

This replaces all IMongoClient, IMongoDatabase, and IMongoCollection<T> registrations in one line.

See Also

Clone this wiki locally